package org.jetbrains.plugins.ruby.motion.run.renderers;
import com.intellij.execution.ExecutionException;
import com.intellij.openapi.util.Pair;
import com.intellij.xdebugger.frame.XCompositeNode;
import com.intellij.xdebugger.frame.XFullValueEvaluator;
import com.jetbrains.cidr.execution.debugger.backend.DebuggerCommandException;
import com.jetbrains.cidr.execution.debugger.backend.LLValue;
import com.jetbrains.cidr.execution.debugger.backend.LLValueData;
import com.jetbrains.cidr.execution.debugger.evaluation.CidrPhysicalValue;
import com.jetbrains.cidr.execution.debugger.evaluation.CidrValue;
import com.jetbrains.cidr.execution.debugger.evaluation.EvaluationContext;
import com.jetbrains.cidr.execution.debugger.evaluation.renderers.ValueRenderer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.ruby.motion.run.MotionMemberValue;
import org.jetbrains.plugins.ruby.ruby.lang.TextUtil;
import java.util.ArrayList;
import java.util.Collection;
/**
* @author Dennis.Ushakov
*/
public class MotionObjectRenderer extends ValueRenderer {
public MotionObjectRenderer(@NotNull CidrPhysicalValue value) {
super(value);
}
@NotNull
@Override
protected Pair<String, XFullValueEvaluator> doComputeValueAndEvaluator(@NotNull EvaluationContext context) throws ExecutionException,
DebuggerCommandException {
LLValue value =
context.evaluate("(char *)[[(id)rb_inspect(" + myValue.getVarData(context).getPointer() + ") description] UTF8String]");
LLValueData data = context.getData(value);
return doComputeValueAndEvaluator(context, value, data);
}
@Override
protected boolean mayHaveChildrenViaChildrenCount() {
return true;
}
@Override
@Nullable
protected Integer doComputeChildrenCount(@NotNull EvaluationContext context) throws ExecutionException, DebuggerCommandException {
return count(context, getInstanceVariablesNames(context));
}
private static int count(EvaluationContext context, LLValue instanceVariablesNames) throws ExecutionException, DebuggerCommandException {
return (int)context.evaluateData(context.castIDToNumber("[" + getSelf(instanceVariablesNames, context) + " count]", "unsigned int")).intValue();
}
private LLValue getInstanceVariablesNames(EvaluationContext context) throws ExecutionException, DebuggerCommandException {
return context.evaluate(EvaluationContext.cast("rb_obj_instance_variables(" + getSelf(context) + ")", "id"));
}
@Override
protected void doComputeChildren(@NotNull EvaluationContext context,
@NotNull XCompositeNode container) throws ExecutionException, DebuggerCommandException {
final Collection<CidrValue> children = new ArrayList<>();
final LLValue names = getInstanceVariablesNames(context);
final int count = count(context, names);
for (int i = 0; i < count; i++) {
final String selName = EvaluationContext.cast("sel_registerName(\"objectAtIndex:\")", "id");
final String nameExpr = EvaluationContext.cast("objc_msgSend(" + getSelf(names, context) + ", " + selName + ", " + i + ")", "id");
final LLValueData name = context.evaluateData(nameExpr);
final String namePointer = "(char *)[[" + name.getPointer() + " description] UTF8String]";
final String ivarName = TextUtil.removeQuoting(context.evaluateData(namePointer).getPresentableValue());
final String ivarExpr = getChildEvaluationExpression(context, ivarName);
final LLValue ivar = context.evaluate(ivarExpr);
children.add(new MotionMemberValue(ivar,
ivarName,
myValue
));
}
CidrValue.addAllTo(children, container);
}
private String getChildEvaluationExpression(@NotNull EvaluationContext context, String ivarName)
throws ExecutionException, DebuggerCommandException {
final String ivarNameExpr = EvaluationContext.cast("rb_intern(\"" + ivarName + "\")", "char *");
return EvaluationContext.cast("rb_ivar_get(" + getSelf(context) + ", " + ivarNameExpr + ")", "id");
}
private String getSelf(@NotNull EvaluationContext context) throws ExecutionException, DebuggerCommandException {
return EvaluationContext.cast(myValue.getVarData(context).getPointer(), "id");
}
private static String getSelf(LLValue value, @NotNull EvaluationContext context) throws DebuggerCommandException, ExecutionException {
return EvaluationContext.cast(context.getData(value).getPointer(), "id");
}
}