blob: 86014ec7949dd17d0eaeb29abe549a62ffdb9694 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2006 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.debug.core;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.model.ISourceLocator;
import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.debug.core.IJavaReferenceType;
import org.eclipse.jdt.debug.core.IJavaStackFrame;
import org.eclipse.jdt.debug.core.IJavaThread;
import org.eclipse.jdt.debug.core.IJavaType;
import org.eclipse.jdt.debug.core.IJavaValue;
import com.sun.jdi.VMDisconnectedException;
/**
* A Utilities class.
*
* @since 3.2
*/
public class JavaDebugUtils {
/**
* Resolves and returns a type from the Java model that corresponds to the
* declaring type of the given stack frame, or <code>null</code> if none.
*
* @param frame frame to resolve declaring type for
* @return correponding Java model type or <code>null</code>
* @exception CoreException if an exception occurrs during the resolution
* @since 3.2
*/
public static IType resolveDeclaringType(IJavaStackFrame frame) throws CoreException {
IJavaElement javaElement = resolveJavaElement(frame, frame.getLaunch());
if (javaElement != null) {
return resolveType(frame.getDeclaringTypeName(), javaElement);
}
return null;
}
/**
* Resolves and returns a type from the Java model that corresponds to the
* type of the given value, or <code>null</code> if none.
*
* @param value value to resolve type for
* @return correponding Java model type or <code>null</code>
* @exception CoreException if an exception occurrs during the resolution
*/
public static IType resolveType(IJavaValue value) throws CoreException {
IJavaElement javaElement = resolveJavaElement(value, value.getLaunch());
if (javaElement != null) {
return resolveType(value.getJavaType().getName(), javaElement);
}
return null;
}
/**
* Resolves and returns the Java model type associcated with the given
* Java debug type, or <code>null</code> if none.
*
* @param type Java debug model type
* @return Java model type or <code>null</code>
* @throws CoreException
*/
public static IType resolveType(IJavaType type) throws CoreException {
IJavaElement element = resolveJavaElement(type, type.getLaunch());
if (element != null ) {
return resolveType(type.getName(), element);
}
return null;
}
/**
* Returns the source name associated with the given object, or <code>null</code>
* if none.
*
* @param object an object with an <code>IJavaStackFrame</code> adapter, an IJavaValue
* or an IJavaType
* @return the source name associated with the given object, or <code>null</code>
* if none
* @exception CoreException if unable to retrieve the source name
*/
public static String getSourceName(Object object) throws CoreException {
if (object instanceof String) {
// assume it's a file name
return (String)object;
}
IJavaStackFrame frame = null;
if (object instanceof IAdaptable) {
frame = (IJavaStackFrame) ((IAdaptable)object).getAdapter(IJavaStackFrame.class);
}
String typeName = null;
try {
if (frame != null) {
if (frame.isObsolete()) {
return null;
}
String sourceName = frame.getSourcePath();
// TODO: this may break fix to bug 21518
if (sourceName == null) {
// no debug attributes, guess at source name
typeName = frame.getDeclaringTypeName();
} else {
return sourceName;
}
} else {
if (object instanceof IJavaValue) {
// look at its type
object = ((IJavaValue)object).getJavaType();
}
if (object instanceof IJavaReferenceType) {
IJavaReferenceType refType = (IJavaReferenceType)object;
String[] sourcePaths = refType.getSourcePaths(null);
if (sourcePaths != null && sourcePaths.length > 0) {
return sourcePaths[0];
}
}
if (object instanceof IJavaType) {
typeName = ((IJavaType)object).getName();
}
}
} catch (DebugException e) {
int code = e.getStatus().getCode();
if (code == IJavaThread.ERR_THREAD_NOT_SUSPENDED || code == IJavaStackFrame.ERR_INVALID_STACK_FRAME ||
e.getStatus().getException() instanceof VMDisconnectedException) {
return null;
}
throw e;
}
if (typeName != null) {
return generateSourceName(typeName);
}
return null;
}
/**
* Generates and returns a source file path based on a qualified type name.
* For example, when <code>java.lang.String</code> is provided,
* the returned source name is <code>java/lang/String.java</code>.
*
* @param qualifiedTypeName fully qualified type name that may contain inner types
* denoted with <code>$</code> character
* @return a source file path corresponding to the type name
*/
public static String generateSourceName(String qualifiedTypeName) {
int index = qualifiedTypeName.lastIndexOf('.');
if (index < 0) {
index = 0;
}
qualifiedTypeName = qualifiedTypeName.replace('.', File.separatorChar);
index = qualifiedTypeName.indexOf('$');
if (index >= 0) {
qualifiedTypeName = qualifiedTypeName.substring(0, index);
}
if (qualifiedTypeName.length() == 0) {
// likely a proxy class (see bug 40815)
qualifiedTypeName = null;
} else {
qualifiedTypeName = qualifiedTypeName + ".java"; //$NON-NLS-1$
}
return qualifiedTypeName;
}
/**
* Resolves the type corresponding to the given name contained in the given top-level
* Java element (class file, compilation unit, or type).
*
* @param qualifiedName fully qualified type name
* @param javaElement java element containing the type
* @return type
* @throws CoreException
*/
private static IType resolveType(String qualifiedName, IJavaElement javaElement) throws CoreException {
IType type = null;
String[] typeNames = getNestedTypeNames(qualifiedName);
if (javaElement instanceof IClassFile) {
type = ((IClassFile)javaElement).getType();
} else if (javaElement instanceof ICompilationUnit) {
type = ((ICompilationUnit)javaElement).getType(typeNames[0]);
} else if (javaElement instanceof IType) {
type = (IType)javaElement;
}
if (type != null) {
for (int i = 1; i < typeNames.length; i++) {
String innerTypeName= typeNames[i];
try {
Integer.parseInt(innerTypeName);
return type;
} catch (NumberFormatException e) {
}
type = type.getType(innerTypeName);
}
}
return type;
}
/**
* Returns the Java element corresponding to the given object or <code>null</code>
* if none, in the context of the given launch.
*
* @param launch provides source locator
* @param object object to resolve Java model element for
* @return corresponding Java element or <code>null</code>
* @throws CoreException
*/
private static IJavaElement resolveJavaElement(Object object, ILaunch launch) throws CoreException {
Object sourceElement = resolveSourceElement(object, launch);
IJavaElement javaElement = null;
if (sourceElement instanceof IJavaElement) {
javaElement = (IJavaElement) sourceElement;
} else if (sourceElement instanceof IAdaptable) {
javaElement = (IJavaElement) ((IAdaptable)sourceElement).getAdapter(IJavaElement.class);
}
if (javaElement == null && sourceElement instanceof IResource) {
javaElement= JavaCore.create((IResource)sourceElement);
}
if (javaElement == null) {
return null;
}
if (!javaElement.exists()) {
return null;
}
return javaElement;
}
/**
* Returns the source element corresponding to the given object or <code>null</code>
* if none, in the context of the given launch.
*
* @param launch provides source locator
* @param object object to resolve source element for
* @return corresponding source element or <code>null</code>
* @throws CoreException
*/
public static Object resolveSourceElement(Object object, ILaunch launch) throws CoreException {
ISourceLocator sourceLocator = launch.getSourceLocator();
if (sourceLocator instanceof ISourceLookupDirector) {
ISourceLookupDirector director = (ISourceLookupDirector) sourceLocator;
Object[] objects = director.findSourceElements(object);
if (objects.length > 0) {
return objects[0];
}
}
return null;
}
/**
* Returns an array of simple type names that are
* part of the given type's qualified name. For
* example, if the given name is <code>x.y.A$B</code>,
* an array with <code>["A", "B"]</code> is returned.
*
* @param typeName fully qualified type name
* @return array of nested type names
*/
private static String[] getNestedTypeNames(String typeName) {
int index = typeName.lastIndexOf('.');
if (index >= 0) {
typeName= typeName.substring(index + 1);
}
index = typeName.indexOf('$');
List list = new ArrayList(1);
while (index >= 0) {
list.add(typeName.substring(0, index));
typeName = typeName.substring(index + 1);
index = typeName.indexOf('$');
}
list.add(typeName);
return (String[])list.toArray(new String[list.size()]);
}
/**
* Returns the class file or comiplation unit containing the given fully qualified name in the
* specified project. All reqistered java like file extensions are considered.
*
* @param qualifiedTypeName fully qualified type name
* @param project project to search in
* @return class file or compilation unit or <code>null</code>
*/
public static IJavaElement findElement(String qualifiedTypeName, IJavaProject project) throws CoreException{
String[] javaLikeExtensions = JavaCore.getJavaLikeExtensions();
String path = qualifiedTypeName;
int pos = path.indexOf('$');
if (pos != -1) {
path= path.substring(0, pos);
}
path = path.replace('.', IPath.SEPARATOR);
path += "."; //$NON-NLS-1$
for (int i = 0; i < javaLikeExtensions.length; i++) {
String ext = javaLikeExtensions[i];
IJavaElement element = project.findElement(new Path(path + ext));
if (element != null) {
return element;
}
}
return null;
}
}