blob: 47fdf9027f26b8a1091237d3c995abc63ed99e63 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013 Christian Pontesegger 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:
* Christian Pontesegger - initial API and implementation
*******************************************************************************/
package org.eclipse.ease.debugging.model;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.model.IDebugElement;
import org.eclipse.debug.core.model.IValue;
public class EaseDebugValue implements IValue {
public static boolean isPrimitiveType(final Object value) {
return (value instanceof Integer) || (value instanceof Byte) || (value instanceof Short) || (value instanceof Boolean) || (value instanceof Character)
|| (value instanceof Long) || (value instanceof Double) || (value instanceof Float);
}
private static Collection<Field> getFields(Class<? extends Object> clazz) {
final Collection<Field> fields = new HashSet<>();
fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
fields.addAll(Arrays.asList(clazz.getFields()));
final Class<?> superclass = clazz.getSuperclass();
if (superclass != null)
fields.addAll(getFields(superclass));
return fields;
}
private IDebugElement fParent;
private Object fValue;
private List<EaseDebugVariable> fVariables = null;
private String fValueString = null;
public EaseDebugValue(final IDebugElement parent, final Object value) {
fParent = parent;
fValue = value;
}
public void setParent(IDebugElement parent) {
fParent = parent;
// do not use getVariables() here as we do not want to deeply populate everything right now.
if (fVariables != null) {
for (final EaseDebugVariable variable : fVariables)
variable.setParent(fParent);
}
}
@Override
public String getReferenceTypeName() {
if (getValue() != null) {
if (isPrimitiveType(getValue())) {
if (getValue() instanceof Integer)
return "int";
if (getValue() instanceof Boolean)
return "bool";
if (getValue() instanceof Character)
return "char";
return fValue.getClass().getSimpleName().toLowerCase();
}
return getValue().getClass().getSimpleName();
}
return "";
}
@Override
public String getValueString() {
if (fValueString != null)
return fValueString;
if (isPrimitiveType(fValue))
return fValue.toString();
if (fValue instanceof String)
return "\"" + fValue + "\" (id=" + getUniqueID(getValue()) + ")";
if (getValue() != null) {
if (getValue().getClass().isArray())
return fValue.getClass().getComponentType().getSimpleName() + "[" + Array.getLength(getValue()) + "] (id=" + getUniqueID(getValue()) + ")";
return fValue.getClass().getSimpleName() + " (id=" + getUniqueID(getValue()) + ")";
} else
return "null";
}
private String getUniqueID(Object value) {
if (getDebugTarget() != null)
return Integer.toString(getDebugTarget().getUniqueVariableId(value));
return "<none>";
}
@Override
public boolean isAllocated() {
return fValue != null;
}
@Override
public <T> T getAdapter(Class<T> adapter) {
if (String.class.equals(adapter))
return (T) ((fValue != null) ? fValue.toString() : "");
return null;
}
@Override
public EaseDebugTarget getDebugTarget() {
// FIXME can we change fParent to EaseDebugElement?
if (fParent != null)
return (EaseDebugTarget) fParent.getDebugTarget();
return null;
}
@Override
public String getModelIdentifier() {
return getDebugTarget().getModelIdentifier();
}
@Override
public ILaunch getLaunch() {
return getDebugTarget().getLaunch();
}
public Object getValue() {
return fValue;
}
@Override
public EaseDebugVariable[] getVariables() {
if (fVariables == null) {
fVariables = new ArrayList<>();
if (getValue() == null)
return new EaseDebugVariable[0];
if (isPrimitiveType(getValue()))
return new EaseDebugVariable[0];
if (getValue().getClass().isArray()) {
final int length = Array.getLength(getValue());
for (int index = 0; index < length; index++) {
final EaseDebugVariable variable = new EaseJavaArrayElementVariable(index, getValue(), fParent);
fVariables.add(variable);
}
} else if (getValue() instanceof Collection<?>) {
final Collection<?> asCollection = (Collection<?>) getValue();
int index = 0;
for (final Object value : asCollection) {
final EaseDebugVariable variable = new EaseDebugVariable(String.format("[%d]", index++), value, fParent, null);
fVariables.add(variable);
}
} else {
// populate generic Java fields
Collection<Field> fields = getFields(getValue().getClass());
fields = fields.stream().filter(field -> !Modifier.isStatic(field.getModifiers())).collect(Collectors.toSet());
for (final Field field : fields) {
try {
field.setAccessible(true);
final EaseDebugVariable variable = new EaseJavaFieldVariable(field, getValue(), fParent);
fVariables.add(variable);
} catch (final IllegalArgumentException e) {
// ignore
} catch (final IllegalAccessException e) {
// ignore
}
}
}
sortVariables();
}
return fVariables.toArray(new EaseDebugVariable[fVariables.size()]);
}
@Override
public boolean hasVariables() {
if (getValue() == null)
return false;
if (isPrimitiveType(getValue()))
return false;
// in case we did not fetch variables yet we delay evaluation and pretend we have children
return (fVariables != null) ? (getVariables().length > 0) : true;
}
public void setVariables(Collection<EaseDebugVariable> variables) {
if (variables != null) {
fVariables = new ArrayList<>(variables);
sortVariables();
}
}
public void update(Object value) {
fValue = value;
fVariables = null;
}
public void setValueString(String valueString) {
fValueString = valueString;
}
private void sortVariables() {
Collections.sort(fVariables, (o1, o2) -> {
final String name1 = o1.getName();
final String name2 = o2.getName();
if ((name1.startsWith("[")) && (name1.endsWith("]")) && (name2.startsWith("[")) && (name2.endsWith("]"))) {
// array operator
try {
final int index1 = Integer.parseInt(name1.substring(1, name1.length() - 1));
final int index2 = Integer.parseInt(name2.substring(1, name2.length() - 1));
return index1 - index2;
} catch (final NumberFormatException e) {
// not a number, ignore and use string compare
}
}
return name1.compareTo(name2);
});
}
}