From 20baa38a22879d7b656ba6d684009188882ec1cc Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Thu, 4 Mar 2010 15:48:37 +0000 Subject: [PATCH] [304588] Return the problem number of children even if GDB counts private/public/protected as a level of children. --- .../cdt/dsf/mi/service/MIExpressions.java | 2 +- .../cdt/dsf/mi/service/MIVariableManager.java | 112 ++++++++++++++---- .../cdt/dsf/mi/service/ClassAccessor.java | 71 +++++++++++ .../dsf/gdb/tests/MIExpressionsTest.java | 94 ++++++++++++++- 4 files changed, 254 insertions(+), 25 deletions(-) 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. */