diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIExpressions.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIExpressions.java
index efea26619c2..f07c1505345 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIExpressions.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIExpressions.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2010 Wind River Systems and others.
+ * Copyright (c) 2006, 2010 Wind River Systems 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
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIVariableManager.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIVariableManager.java
index 19c1f865bc3..da4d35e3fdc 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIVariableManager.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIVariableManager.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2010 Monta Vista and others.
+ * Copyright (c) 2008, 2010 Monta Vista 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
@@ -210,7 +210,10 @@ public class MIVariableManager implements ICommandControl {
private String fullExp = null;
private String type = null;
private GDBType gdbType;
- private int numChildren = 0;
+ // A hint at the number of children. This value is obtained
+ // from -var-create or -var-list-children. It may not be right in the case
+ // of C++ structures, where GDB has a level of children for private/public/protected.
+ private int numChildrenHint = 0;
private Boolean editable = null;
// The current values of the expression for each format. (null if not known yet)
@@ -260,7 +263,33 @@ public class MIVariableManager implements ICommandControl {
/** @since 3.0 */
public GDBType getGDBType() { return gdbType; }
- public int getNumChildren() { return numChildren; }
+ /**
+ * Returns a hint to the number of children. This hint is often correct,
+ * except when we are dealing with C++ complex structures where
+ * GDB has 'private/public/protected' as children.
+ *
+ * Use isNumChildrenHintTrustworthy()
to know if the
+ * hint can be trusted.
+ *
+ * Note that a hint of 0 children can always be trusted.
+ *
+ * @since 3.0 */
+ public int getNumChildrenHint() { return numChildrenHint; }
+ /**
+ * Returns whether the number of children hint can be
+ * trusted for this variable object.
+ *
+ * @since 3.0
+ */
+ public boolean isNumChildrenHintTrustworthy() {
+ // For complex structures which are not arrays, we cannot trust the hint.
+ // This is only valid for C++, so we should even check for it using
+ // -var-info-expression. Do we have to use -var-info-expression for each
+ // variable object, or can we do it one time ony for the whole program?
+ // Right now, we always assume we could be using C++
+ return (!isComplex() || isArray());
+ }
+
public String getValue(String format) { return valueMap.get(format); }
public ExpressionInfo[] getChildren() { return children; }
@@ -270,8 +299,9 @@ public class MIVariableManager implements ICommandControl {
public boolean isPointer() { return (getGDBType() == null) ? false : getGDBType().getType() == GDBType.POINTER; }
public boolean isMethod() { return (getGDBType() == null) ? false : getGDBType().getType() == GDBType.FUNCTION; }
// A complex variable is one with children. However, it must not be a pointer since a pointer has one child
- // according to GDB, but is still a 'simple' variable
- public boolean isComplex() { return (getGDBType() == null) ? false : getGDBType().getType() != GDBType.POINTER && getNumChildren() > 0; }
+ // according to GDB, but is still a 'simple' variable.
+ // Note that the numChildrenHint can be trusted when asking if the number of children is 0 or not
+ public boolean isComplex() { return (getGDBType() == null) ? false : getGDBType().getType() != GDBType.POINTER && getNumChildrenHint() > 0; }
public void setGdbName(String n) { gdbName = n; }
public void setCurrentFormat(String f) { format = f; }
@@ -280,7 +310,7 @@ public class MIVariableManager implements ICommandControl {
fullExp = fullExpression;
type = t;
gdbType = fGDBTypeParser.parse(t);
- numChildren = num;
+ numChildrenHint = num;
}
public void setValue(String format, String val) { valueMap.put(format, val); }
@@ -591,7 +621,9 @@ public class MIVariableManager implements ICommandControl {
}
// If the variable does not have children, we can return an empty list right away
- if (getNumChildren() == 0) {
+ // The numChildrenHint value is trustworthy when wanting to know if there are children
+ // at all.
+ if (getNumChildrenHint() == 0) {
// First store the empty list, for the next time
setChildren(new ExpressionInfo[0]);
rm.setData(getChildren());
@@ -604,7 +636,8 @@ public class MIVariableManager implements ICommandControl {
// never need. Using -var-list-children will create a variable object for every child
// immediately, that is why won't don't want to use it for arrays.
if (isArray()) {
- ExpressionInfo[] childrenOfArray = new ExpressionInfo[getNumChildren()];
+ // We can trust the numChildrenHint value for arrays.
+ ExpressionInfo[] childrenOfArray = new ExpressionInfo[getNumChildrenHint()];
for (int i= 0; i < childrenOfArray.length; i++) {
String indexStr = "[" + i + "]";//$NON-NLS-1$//$NON-NLS-2$
String fullExpr = exprDmc.getExpression() + indexStr;
@@ -794,11 +827,22 @@ public class MIVariableManager implements ICommandControl {
* @param rm
* The data request monitor that will hold the count of children returned
*/
- private void getChildrenCount(final DataRequestMonitor rm) {
- // No need to lock the object or wait for it to be ready since this operation does not
- // affect other operations
- rm.setData(getNumChildren());
- rm.done();
+ private void getChildrenCount(MIExpressionDMC exprDmc, final DataRequestMonitor rm) {
+ if (isNumChildrenHintTrustworthy()){
+ rm.setData(getNumChildrenHint());
+ rm.done();
+ return;
+ }
+
+ getChildren(
+ exprDmc,
+ new DataRequestMonitor(fSession.getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ rm.setData(getData().length);
+ rm.done();
+ }
+ });
}
@@ -1590,15 +1634,36 @@ public class MIVariableManager implements ICommandControl {
new DataRequestMonitor(fSession.getExecutor(), drm) {
@Override
protected void handleSuccess() {
- drm.setData(
- new ExprMetaGetVarInfo(
- exprCtx.getRelativeExpression(),
- getData().getNumChildren(),
- getData().getType(),
- getData().getGDBType(),
- !getData().isComplex()));
- drm.done();
- processCommandDone(token, drm.getData());
+ final MIVariableObject varObj = getData();
+ if (varObj.isNumChildrenHintTrustworthy()) {
+ drm.setData(
+ new ExprMetaGetVarInfo(
+ exprCtx.getRelativeExpression(),
+ getData().getNumChildrenHint(),
+ getData().getType(),
+ getData().getGDBType(),
+ !getData().isComplex()));
+ drm.done();
+ processCommandDone(token, drm.getData());
+ } else {
+ // We have to ask for the children count because the hint could be wrong
+ varObj.getChildrenCount(
+ exprCtx,
+ new DataRequestMonitor(fSession.getExecutor(), drm) {
+ @Override
+ protected void handleSuccess() {
+ drm.setData(
+ new ExprMetaGetVarInfo(
+ exprCtx.getRelativeExpression(),
+ getData(),
+ varObj.getType(),
+ varObj.getGDBType(),
+ !varObj.isComplex()));
+ drm.done();
+ processCommandDone(token, drm.getData());
+ }
+ });
+ }
}
});
} else if (command instanceof ExprMetaGetAttributes) {
@@ -1675,7 +1740,7 @@ public class MIVariableManager implements ICommandControl {
} else if (command instanceof ExprMetaGetChildCount) {
@SuppressWarnings("unchecked")
final DataRequestMonitor drm = (DataRequestMonitor)rm;
- final IExpressionDMContext exprCtx = (IExpressionDMContext)(command.getContext());
+ final MIExpressionDMC exprCtx = (MIExpressionDMC)(command.getContext());
getVariable(
exprCtx,
@@ -1683,6 +1748,7 @@ public class MIVariableManager implements ICommandControl {
@Override
protected void handleSuccess() {
getData().getChildrenCount(
+ exprCtx,
new DataRequestMonitor(fSession.getExecutor(), drm) {
@Override
protected void handleSuccess() {
diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/ClassAccessor.java b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/ClassAccessor.java
index 834f7189c50..a90542d47b6 100644
--- a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/ClassAccessor.java
+++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/ClassAccessor.java
@@ -10,7 +10,13 @@
*******************************************************************************/
package org.eclipse.cdt.dsf.mi.service;
+import java.util.Map;
+
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMData;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMData.BasicType;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMContext;
+import org.eclipse.cdt.dsf.mi.service.MIExpressions.ExpressionDMData;
import org.eclipse.cdt.dsf.mi.service.MIExpressions.MIExpressionDMC;
public class ClassAccessor {
@@ -45,4 +51,69 @@ public class ClassAccessor {
return miExprDmc.getRelativeExpression();
}
}
+
+ public static class ExpressionDMDataAccessor {
+ private ExpressionDMData miExprData;
+
+ public ExpressionDMDataAccessor(IExpressionDMData data) {
+ miExprData = (ExpressionDMData) data;
+ }
+
+ public BasicType getBasicType() {
+ return miExprData.getBasicType();
+ }
+
+ public String getEncoding() {
+ return miExprData.getEncoding();
+ }
+
+ public Map getEnumerations() {
+ return miExprData.getEnumerations();
+ }
+
+ public String getName() {
+ return miExprData.getName();
+ }
+
+ public IRegisterDMContext getRegister() {
+ return miExprData.getRegister();
+ }
+
+ public String getStringValue() {
+ return miExprData.getStringValue();
+ }
+
+ public String getTypeId() {
+ return miExprData.getTypeId();
+ }
+
+ public String getTypeName() {
+ return miExprData.getTypeName();
+ }
+
+ public int getNumChildren() {
+ return miExprData.getNumChildren();
+ }
+
+ public boolean isEditable() {
+ return miExprData.isEditable();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return miExprData.equals(other);
+ }
+
+ @Override
+ public int hashCode() {
+ return miExprData.hashCode();
+
+ }
+
+ @Override
+ public String toString() {
+ return miExprData.toString();
+
+ }
+ }
}
diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/MIExpressionsTest.java b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/MIExpressionsTest.java
index bac54500557..53e72edef5a 100644
--- a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/MIExpressionsTest.java
+++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/MIExpressionsTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007 Ericsson and others.
+ * Copyright (c) 2007, 2010 Ericsson 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
@@ -32,6 +32,7 @@ import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMData;
import org.eclipse.cdt.dsf.debug.service.IRunControl.StepType;
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
import org.eclipse.cdt.dsf.mi.service.MIExpressions;
+import org.eclipse.cdt.dsf.mi.service.ClassAccessor.ExpressionDMDataAccessor;
import org.eclipse.cdt.dsf.mi.service.ClassAccessor.MIExpressionDMCAccessor;
import org.eclipse.cdt.dsf.mi.service.command.events.MIStoppedEvent;
import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
@@ -291,6 +292,97 @@ public class MIExpressionsTest extends BaseTestCase {
doTestChildren(stoppedEvent);
}
+ /**
+ * This test makes sure we get the right number of children.
+ */
+ @Test
+ public void testChildrenCount() throws Throwable {
+ // Next we test that we can retrieve children count while reading the
+ // value and vice-versa
+
+ SyncUtil.runToLocation("testChildren");
+ MIStoppedEvent stoppedEvent = SyncUtil.step(1, StepType.STEP_OVER);
+
+ final IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0);
+
+ final AsyncCompletionWaitor wait = new AsyncCompletionWaitor();
+
+ // First we get the expected value of the array pointer.
+ final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, "f");
+
+ fExpService.getExecutor().submit(new Runnable() {
+ public void run() {
+ fExpService.getSubExpressionCount(
+ exprDmc,
+ new DataRequestMonitor(fExpService.getExecutor(), null) {
+ @Override
+ protected void handleCompleted() {
+ if (!isSuccess()) {
+ wait.waitFinished(getStatus());
+ } else {
+ int count = getData();
+ if (count != 5) {
+ wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID,
+ "Failed getting count for children. Got " + count + " instead of 5", null));
+ } else {
+ wait.waitFinished();
+ }
+ }
+ }
+ });
+ }
+ });
+
+ wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER);
+ assertTrue(wait.getMessage(), wait.isOK());
+ }
+
+ /**
+ * This test makes sure we get the right number of children.
+ */
+ @Test
+ public void testChildrenCountInExpressionData() throws Throwable {
+ // Next we test that we can retrieve children count while reading the
+ // value and vice-versa
+
+ SyncUtil.runToLocation("testChildren");
+ MIStoppedEvent stoppedEvent = SyncUtil.step(1, StepType.STEP_OVER);
+
+ final IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0);
+
+ final AsyncCompletionWaitor wait = new AsyncCompletionWaitor();
+
+ // First we get the expected value of the array pointer.
+ final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, "f");
+
+ fExpService.getExecutor().submit(new Runnable() {
+ public void run() {
+ fExpService.getExpressionData(
+ exprDmc,
+ new DataRequestMonitor(fExpService.getExecutor(), null) {
+ @Override
+ protected void handleCompleted() {
+ if (!isSuccess()) {
+ wait.waitFinished(getStatus());
+ } else {
+ ExpressionDMDataAccessor data = new ExpressionDMDataAccessor(getData());
+ int count = data.getNumChildren();
+ if (count != 5) {
+ wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID,
+ "Failed getting count for children. Got " + count + " instead of 5", null));
+ } else {
+ wait.waitFinished();
+ }
+ }
+ }
+ });
+ }
+ });
+
+ wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER);
+ assertTrue(wait.getMessage(), wait.isOK());
+ }
+
/**
* This test verifies that the ExpressionService can write to a variable.
*/