1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-23 14:42:11 +02:00

[304588] Return the problem number of children even if GDB counts private/public/protected as a level of children.

This commit is contained in:
Marc Khouzam 2010-03-04 15:48:37 +00:00
parent f642b20a88
commit 20baa38a22
4 changed files with 254 additions and 25 deletions

View file

@ -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

View file

@ -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 <code>isNumChildrenHintTrustworthy()</code> 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<Integer> 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<Integer> rm) {
if (isNumChildrenHintTrustworthy()){
rm.setData(getNumChildrenHint());
rm.done();
return;
}
getChildren(
exprDmc,
new DataRequestMonitor<ExpressionInfo[]>(fSession.getExecutor(), rm) {
@Override
protected void handleSuccess() {
rm.setData(getData().length);
rm.done();
}
});
}
@ -1590,15 +1634,36 @@ public class MIVariableManager implements ICommandControl {
new DataRequestMonitor<MIVariableObject>(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<Integer>(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<ExprMetaGetChildCountInfo> drm = (DataRequestMonitor<ExprMetaGetChildCountInfo>)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<Integer>(fSession.getExecutor(), drm) {
@Override
protected void handleSuccess() {

View file

@ -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<String, Integer> 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();
}
}
}

View file

@ -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<Integer>(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<IExpressionDMData>(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.
*/