From ee0eb1bb4811d40bb9380f743421122d9cafa635 Mon Sep 17 00:00:00 2001 From: Sergey Prigogin Date: Wed, 25 Jan 2012 16:11:05 -0800 Subject: [PATCH 1/4] Bug 352258 - Generate Getters and Setters can generate code containing reserved keywords. --- .../src/org/eclipse/cdt/core/CConventions.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CConventions.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CConventions.java index 330d94e220a..f88b9830d4d 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CConventions.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CConventions.java @@ -291,8 +291,8 @@ public class CConventions { if (!isValidIdentifier(id)) { return new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, -1, NLS.bind(Messages.convention_invalid, id), null); } - - if (isReservedKeyword(id, language)) { + + if (isReservedKeyword(id, language) || isBuiltinType(id, language)) { return new Status(IStatus.ERROR, CCorePlugin.PLUGIN_ID, -1, NLS.bind(Messages.convention_reservedKeyword, id), null); } @@ -369,7 +369,16 @@ public class CConventions { } return false; } - + + private static boolean isBuiltinType(String name, AbstractCLikeLanguage language) { + String[] types = language.getBuiltinTypes(); + for (String type : types) { + if (type.equals(name)) + return true; + } + return false; + } + private static boolean isLegalFilename(String name) { if (name == null || name.isEmpty()) { return false; From 15ab0165f1bfae5ff780536d134902ff7592ff8e Mon Sep 17 00:00:00 2001 From: Mikhail Khodjaiants Date: Thu, 26 Jan 2012 11:59:27 -0500 Subject: [PATCH 2/4] =?UTF-8?q?Bug=20365541=20-=20View=20an=20array=20vari?= =?UTF-8?q?able=20whose=20length=20is=20very=20long=20=EF=BC=88such=20as?= =?UTF-8?q?=2010000=EF=BC=89=20in=20the=20editor=20or=20Variable=20View,?= =?UTF-8?q?=20will=20cause=20the=20interface=20to=20die.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../icons/obj16/arraypartition_obj.gif | Bin 0 -> 370 bytes .../cdt/debug/internal/ui/CDebugImages.java | 2 + .../cdt/dsf/mi/service/MIExpressions.java | 417 +++++++++++++++--- .../cdt/dsf/mi/service/MIVariableManager.java | 4 + .../data/launch/src/ExpressionTestApp.cc | 9 + .../dsf/gdb/tests/MIExpressionsTest.java | 169 +++++-- .../ui/viewmodel/DsfCastToTypeSupport.java | 4 + .../ui/viewmodel/variable/VariableVMNode.java | 61 ++- .../cdt/dsf/debug/service/IExpressions.java | 24 + 9 files changed, 590 insertions(+), 100 deletions(-) create mode 100755 debug/org.eclipse.cdt.debug.ui/icons/obj16/arraypartition_obj.gif diff --git a/debug/org.eclipse.cdt.debug.ui/icons/obj16/arraypartition_obj.gif b/debug/org.eclipse.cdt.debug.ui/icons/obj16/arraypartition_obj.gif new file mode 100755 index 0000000000000000000000000000000000000000..052915a19b0450569ed92323067f65a3372bcaee GIT binary patch literal 370 zcmZ?wbhEHb6krfwxXQqg)v)^0*WcfM{Q3I*_s?H{e*FAh)UmN<;*OSC``YIm$nV{G z@5T2=uYbIF|MUCLKi_`*zW4ISgI7Q9zx@8-)%T}wf82Zd{n48r@4x(VFJ9_Zz9OJz zO<2RmH=ll*6fBcYp4V9BS6AY{bY4q)rB73t-}%FHr#HDxs`u!r_PTUr-o+#HHul@C z?X_Rg<+!-rd2Wl#mI=0}H&ryJ7^R0z5S$Y~qb?SyAE@z#H1a!suurz{BF8Xcl96j_LT}iDDdS&esywt+@UE zP*}qH8^6D6a5?FTbBargONmR0ONeVqJE_V{k)1Mqii)h08t**01q&BBsf#S*5m_O& zQq06zNsLpBLyTRFO^iX<$XQuXR8VNYAh)0Zx4g5W!kM$@6cpVqUB2St$Y2cs6BV5d literal 0 HcmV?d00001 diff --git a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/CDebugImages.java b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/CDebugImages.java index 5387b5e2d1c..26c89c64e33 100644 --- a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/CDebugImages.java +++ b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/CDebugImages.java @@ -104,6 +104,7 @@ public class CDebugImages { public static final String IMG_OBJS_PATH_MAPPING = NAME_PREFIX + "mapping_obj.gif"; //$NON-NLS-1$ public static final String IMG_OBJS_PATH_MAP_ENTRY = NAME_PREFIX + "mapentry_obj.gif"; //$NON-NLS-1$ public static final String IMG_OBJS_COMMON_TAB = NAME_PREFIX + "common_tab.gif"; //$NON-NLS-1$ + public static final String IMG_OBJS_ARRAY_PARTITION = NAME_PREFIX + "arraypartition_obj.gif"; //$NON-NLS-1$ public static final String IMG_LCL_TYPE_NAMES = NAME_PREFIX + "tnames_co.gif"; //$NON-NLS-1$ public static final String IMG_LCL_CHANGE_REGISTER_VALUE = NAME_PREFIX + "change_reg_value_co.gif"; //$NON-NLS-1$ @@ -188,6 +189,7 @@ public class CDebugImages { public static final ImageDescriptor DESC_OBJS_PATH_MAPPING = createManaged(T_OBJ, IMG_OBJS_PATH_MAPPING); public static final ImageDescriptor DESC_OBJS_PATH_MAP_ENTRY = createManaged(T_OBJ, IMG_OBJS_PATH_MAP_ENTRY); public static final ImageDescriptor DESC_OBJS_COMMON_TAB = createManaged(T_OBJ, IMG_OBJS_COMMON_TAB); + public static final ImageDescriptor DESC_OBJS_ARRAY_PARTITION = createManaged(T_OBJ, IMG_OBJS_ARRAY_PARTITION); public static final ImageDescriptor DESC_WIZBAN_ADD_SOURCE = createManaged(T_WIZBAN, IMG_WIZBAN_ADD_SOURCE); public static final ImageDescriptor DESC_WIZBAN_PATH_MAPPING = createManaged(T_WIZBAN, IMG_WIZBAN_PATH_MAPPING); public static final ImageDescriptor DESC_WIZBAN_PATH_MAP_ENTRY = createManaged(T_WIZBAN, IMG_WIZBAN_PATH_MAP_ENTRY); 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 9f978a8a274..9b518666d06 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 @@ -13,12 +13,14 @@ *******************************************************************************/ package org.eclipse.cdt.dsf.mi.service; +import java.util.Arrays; import java.util.HashMap; import java.util.Hashtable; import java.util.Map; import org.eclipse.cdt.core.IAddress; import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor; import org.eclipse.cdt.dsf.concurrent.ImmediateRequestMonitor; import org.eclipse.cdt.dsf.concurrent.RequestMonitor; import org.eclipse.cdt.dsf.datamodel.AbstractDMContext; @@ -71,6 +73,8 @@ import org.osgi.framework.BundleContext; */ public class MIExpressions extends AbstractDsfService implements IMIExpressions, ICachingService { + private static final int PARTITION_LENGTH = 100; + /** * A format that gives more details about an expression and supports pretty-printing * provided by the backend. @@ -381,7 +385,7 @@ public class MIExpressions extends AbstractDsfService implements IMIExpressions, this.exprInfo = info; } } - + protected static class InvalidContextExpressionDMC extends AbstractDMContext implements IExpressionDMContext { @@ -413,6 +417,86 @@ public class MIExpressions extends AbstractDsfService implements IMIExpressions, return expression; } } + + /** + * @since 4.1 + */ + protected static class IndexedPartitionDMC extends MIExpressionDMC implements IIndexedPartitionDMContext { + + final private ExpressionInfo fParentInfo; + private final int fIndex; + private final int fLength; + + public IndexedPartitionDMC( + String sessionId, + ExpressionInfo parentInfo, + IFrameDMContext frameCtx, + int index, + int length) { + this(sessionId, parentInfo, (IDMContext)frameCtx, index, length); + } + + private IndexedPartitionDMC( + String sessionId, + ExpressionInfo parentInfo, + IDMContext parent, + int index, + int length) { + super(sessionId, createExpressionInfo(parentInfo, index, length), parent); + fIndex = index; + fLength = length; + fParentInfo = parentInfo; + } + + public ExpressionInfo getParentInfo() { + return fParentInfo; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.dsf.debug.service.IExpressions4.IIndexedPartitionDMContext#getParentExpression() + */ + @Override + public String getParentExpression() { + return getParentInfo().getFullExpr(); + } + + @Override + public int getIndex() { + return fIndex; + } + + @Override + public int getLength() { + return fLength; + } + + @Override + public boolean equals(Object other) { + return super.baseEquals(other) && + ((IndexedPartitionDMC) other).getParentInfo().equals(getParentInfo()) && + ((IndexedPartitionDMC) other).getIndex() == getIndex() && + ((IndexedPartitionDMC) other).getLength() == getLength(); + } + + @Override + public int hashCode() { + return super.baseHashCode() + 17*getIndex() + 31*getLength(); + } + + @Override + public String toString() { + return String.format( "%s[%d-%d]", baseToString(), Integer.valueOf( getIndex() ), Integer.valueOf( getIndex() + getLength() ) ); //$NON-NLS-1$ + } + + private static ExpressionInfo createExpressionInfo(ExpressionInfo parentInfo, int index, int length) { + String expression = String.format( + "*((%s)+%d)@%d", //$NON-NLS-1$ + parentInfo.getFullExpr(), + Integer.valueOf(index), + Integer.valueOf(length)); + return new ExpressionInfo(expression, expression); + } + } /** @@ -1064,33 +1148,8 @@ public class MIExpressions extends AbstractDsfService implements IMIExpressions, * The data request monitor that will contain the requested data */ @Override - public void getSubExpressions(final IExpressionDMContext dmc, - final DataRequestMonitor rm) - { - if (dmc instanceof MIExpressionDMC) { - fExpressionCache.execute( - new ExprMetaGetChildren(dmc), - new DataRequestMonitor(getExecutor(), rm) { - @Override - protected void handleSuccess() { - ExpressionInfo[] childrenExpr = getData().getChildrenExpressions(); - IExpressionDMContext[] childArray = new IExpressionDMContext[childrenExpr.length]; - for (int i=0; i rm) { + getSubExpressions(dmc, -1, -1, rm); } /** @@ -1112,37 +1171,48 @@ public class MIExpressions extends AbstractDsfService implements IMIExpressions, public void getSubExpressions(final IExpressionDMContext exprCtx, final int startIndex, final int length, final DataRequestMonitor rm) { - if (startIndex < 0 || length < 0) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid range for evaluating sub expressions.", null)); //$NON-NLS-1$ - rm.done(); - return; + if (exprCtx instanceof IndexedPartitionDMC) { + getIndexedPartitionChildren((IndexedPartitionDMC)exprCtx, startIndex, length, rm); } - - if (exprCtx instanceof MIExpressionDMC) { - fExpressionCache.execute( - new ExprMetaGetChildren(exprCtx, startIndex + length), - new DataRequestMonitor(getExecutor(), rm) { - @Override - protected void handleSuccess() { - ExpressionInfo[] childrenExpr = getData().getChildrenExpressions(); - - if (startIndex >= childrenExpr.length) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, "Invalid range for evaluating sub expressions.", null)); //$NON-NLS-1$ - rm.done(); - return; - } - - int numChildren = childrenExpr.length - startIndex; - numChildren = Math.min(length, numChildren); - IExpressionDMContext[] childrenArray = new IExpressionDMContext[numChildren]; - for (int i=0; i < numChildren; i++) { - childrenArray[i] = createExpression( - exprCtx.getParents()[0], childrenExpr[startIndex + i]); - } - rm.setData(childrenArray); + else if (exprCtx instanceof MIExpressionDMC) { + getRealSubExpressionCount( + exprCtx, + IMIExpressions.CHILD_COUNT_LIMIT_UNSPECIFIED, + new DataRequestMonitor(getExecutor(), rm) { + /* (non-Javadoc) + * @see org.eclipse.cdt.dsf.concurrent.RequestMonitor#handleSuccess() + */ + @Override + protected void handleSuccess() { + final int realNumChildren = getData().intValue(); + if (realNumChildren == 0) { + rm.setData(new IExpressionDMContext[0]); rm.done(); + return; } - }); + + if (realNumChildren <= getArrayPartitionLength()) { + getRealSubExpressions(exprCtx, startIndex, length, rm); + } + else { + getExpressionData( + exprCtx, + new DataRequestMonitor(ImmediateExecutor.getInstance(), rm) { + + @Override + protected void handleSuccess() { + if (IExpressionDMData.BasicType.array.equals(getData().getBasicType())) { + rm.setData(getTopLevelIndexedPartitions((MIExpressionDMC)exprCtx, realNumChildren, startIndex, length )); + rm.done(); + } + else { + getRealSubExpressions(exprCtx, startIndex, length, rm); + } + } + }); + } + } + }); } else if (exprCtx instanceof InvalidContextExpressionDMC) { rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context for evaluating expressions.", null)); //$NON-NLS-1$ rm.done(); @@ -1183,19 +1253,48 @@ public class MIExpressions extends AbstractDsfService implements IMIExpressions, * @since 4.0 */ @Override - public void getSubExpressionCount(IExpressionDMContext dmc, + public void getSubExpressionCount(final IExpressionDMContext dmc, final int numChildLimit, final DataRequestMonitor rm) { if (dmc instanceof MIExpressionDMC) { - fExpressionCache.execute( - new ExprMetaGetChildCount(dmc, numChildLimit), - new DataRequestMonitor(getExecutor(), rm) { + if (dmc instanceof IndexedPartitionDMC) { + int length = ((IndexedPartitionDMC)dmc).getLength(); + rm.setData(computeNumberOfChildren(length)); + rm.done(); + } + else { + getRealSubExpressionCount( + dmc, + numChildLimit, + new DataRequestMonitor(getExecutor(), rm) { + @Override protected void handleSuccess() { - rm.setData(getData().getChildNum()); - rm.done(); - } + final int realNum = getData().intValue(); + if (realNum <= getArrayPartitionLength()) { + rm.setData(Integer.valueOf(realNum)); + rm.done(); + } + else { + getExpressionData( + dmc, + new DataRequestMonitor(ImmediateExecutor.getInstance(), rm) { + + @Override + protected void handleSuccess() { + if (IExpressionDMData.BasicType.array.equals(getData().getBasicType())) { + rm.setData(computeNumberOfChildren(realNum)); + } + else { + rm.setData(Integer.valueOf(realNum)); + } + rm.done(); + } + }); + } + } }); + } } else if (dmc instanceof InvalidContextExpressionDMC) { rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context for evaluating expressions.", null)); //$NON-NLS-1$ rm.done(); @@ -1442,4 +1541,196 @@ public class MIExpressions extends AbstractDsfService implements IMIExpressions, } }); } + + private IndexedPartitionDMC[] getTopLevelIndexedPartitions( + MIExpressionDMC exprCtx, + int realNumChildren, + int startIndex, + int length) { + + int numChildren = computeNumberOfChildren(realNumChildren); + if (startIndex >= numChildren) + return new IndexedPartitionDMC[0]; + int startIndex1 = (startIndex < 0) ? 0 : startIndex; + int length1 = (length < 0) ? numChildren - startIndex1 : Math.min(length, numChildren - startIndex1); + + IndexedPartitionDMC[] children = new IndexedPartitionDMC[numChildren]; + int index = 0; + for(int i = 0; i < children.length; ++i) { + int partLength = computePartitionLength(realNumChildren, i); + children[i] = createIndexedPartition( + exprCtx.getParents()[0], + exprCtx.getExpressionInfo(), + index, + partLength); + index += partLength; + } + return Arrays.copyOfRange(children, startIndex1, startIndex1 + length1 ); + } + + private void getIndexedPartitionChildren( + final IndexedPartitionDMC partDmc, + final int startIndex, + final int length, + final DataRequestMonitor rm) { + + final int startIndex1 = (startIndex < 0) ? 0 : startIndex; + final int length1 = (length < 0) ? Integer.MAX_VALUE : length; + + final int partStartIndex = partDmc.getIndex(); + final int partLength = partDmc.getLength(); + if (partLength > getArrayPartitionLength()) { + // create subpartitions + int numChildren = computeNumberOfChildren(partLength); + + if (startIndex1 >= numChildren) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, "Invalid range for evaluating sub expressions.", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + int numPart = Math.min(numChildren, length1); + IndexedPartitionDMC[] children = new IndexedPartitionDMC[numPart]; + int index = partStartIndex; + for (int i = 0; i < startIndex1; ++i) + index += computePartitionLength(partLength, i); + for (int i = 0; i < children.length; ++i) { + int childPartLength = computePartitionLength(partLength, i + startIndex1); + children[i] = createIndexedPartition( + partDmc, + partDmc.getParentInfo(), + index, + childPartLength); + index += childPartLength; + } + rm.setData(children); + rm.done(); + } + else { + // this is the last partition level, create "real" children + if (startIndex1 > partLength) { + rm.setData(new IExpressionDMContext[0]); + rm.done(); + } + else { + getRealSubExpressions( + createExpression(partDmc.getParents()[0], partDmc.getParentInfo()), + partStartIndex + startIndex1, + Math.min(length1, partLength - startIndex1), + rm); + } + } + } + + void getRealSubExpressions( + final IExpressionDMContext exprCtx, + int startIndex, + int length, + final DataRequestMonitor rm) { + + ExprMetaGetChildren getChildren = (startIndex < 0 || length < 0) ? + new ExprMetaGetChildren(exprCtx) : new ExprMetaGetChildren(exprCtx, startIndex + length); + final int startIndex1 = (startIndex < 0) ? 0 : startIndex; + final int length1 = (length < 0) ? Integer.MAX_VALUE : length; + fExpressionCache.execute( + getChildren, + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + ExpressionInfo[] childrenExpr = getData().getChildrenExpressions(); + + if (startIndex1 >= childrenExpr.length) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, "Invalid range for evaluating sub expressions.", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + int numChildren = childrenExpr.length - startIndex1; + numChildren = Math.min(length1, numChildren); + IExpressionDMContext[] childrenArray = new IExpressionDMContext[numChildren]; + for (int i=0; i < numChildren; i++) { + childrenArray[i] = createExpression(exprCtx.getParents()[0], childrenExpr[startIndex1 + i]); + } + rm.setData(childrenArray); + rm.done(); + } + }); + } + + /** + * Returns the number of "real" children if it is less or equal to the partition size, + * otherwise returns the number of partitions. + */ + private int computeNumberOfChildren(int realNumberOfChildren) { + int childNum = realNumberOfChildren; + int partLength = getArrayPartitionLength(); + while (childNum > partLength) { + childNum /= partLength; + } + if (childNum*partLength < realNumberOfChildren) + ++childNum; + return childNum; + } + + private int computePartitionLength(int realNumberOfChildren, int index) { + int childNum = realNumberOfChildren; + int depth = 0; + int partLength = getArrayPartitionLength(); + int length = partLength; + while (childNum > partLength) { + childNum /= partLength; + if (depth > 0) + length *= partLength; + ++depth; + } + int diff = realNumberOfChildren - length*index; + return ( diff > length ) ? length : diff ; + } + + private IndexedPartitionDMC createIndexedPartition(IDMContext ctx, ExpressionInfo info, int index, int length) { + IFrameDMContext frameDmc = DMContexts.getAncestorOfType(ctx, IFrameDMContext.class); + if (frameDmc != null) { + return new IndexedPartitionDMC(getSession().getId(), info, frameDmc, index, length); + } + + IMIExecutionDMContext execCtx = DMContexts.getAncestorOfType(ctx, IMIExecutionDMContext.class); + if (execCtx != null) { + // If we have a thread context but not a frame context, we give the user + // the expression as per the top-most frame of the specified thread. + // To do this, we create our own frame context. + MIStack stackService = getServicesTracker().getService(MIStack.class); + if (stackService != null) { + frameDmc = stackService.createFrameDMContext(execCtx, 0); + return new IndexedPartitionDMC(getSession().getId(), info, frameDmc, index, length); + } + } + + return new IndexedPartitionDMC(getSession().getId(), info, ctx, index, length); + } + + private void getRealSubExpressionCount(IExpressionDMContext dmc, int numChildLimit, final DataRequestMonitor rm) { + if (dmc instanceof MIExpressionDMC) { + fExpressionCache.execute( + new ExprMetaGetChildCount(dmc, numChildLimit), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + rm.setData(getData().getChildNum()); + rm.done(); + } + }); + } else if (dmc instanceof InvalidContextExpressionDMC) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context for evaluating expressions.", null)); //$NON-NLS-1$ + rm.done(); + } else { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid expression context.", null)); //$NON-NLS-1$ + rm.done(); + } + } + + private int getArrayPartitionLength() { + // Replace this in case we or the platform decide to add a user preference. + // See org.eclipse.debug.internal.ui.model.elements.VariableContentProvider. + return PARTITION_LENGTH; + } } 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 1636f919ede..2aa69e0d216 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 @@ -31,6 +31,7 @@ import org.eclipse.cdt.dsf.concurrent.RequestMonitor; import org.eclipse.cdt.dsf.datamodel.DMContexts; import org.eclipse.cdt.dsf.debug.service.IExpressions; import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext; +import org.eclipse.cdt.dsf.debug.service.IExpressions.IIndexedPartitionDMContext; import org.eclipse.cdt.dsf.debug.service.IExpressions2.ICastedExpressionDMContext; import org.eclipse.cdt.dsf.debug.service.IFormattedValues; import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContext; @@ -1274,6 +1275,9 @@ public class MIVariableManager implements ICommandControl { exprName = '(' + exprName + ')'; castingIndex = ((ICastedExpressionDMContext)exprDmc).getCastInfo().getArrayStartIndex(); } + if (exprDmc instanceof IIndexedPartitionDMContext) { + castingIndex = ((IIndexedPartitionDMContext)exprDmc).getIndex(); + } for (int i= 0; i < childrenOfArray.length; i++) { String fullExpr = exprName + "[" + i + "]";//$NON-NLS-1$//$NON-NLS-2$ String relExpr = exprDmc.getRelativeExpression() + "[" + (castingIndex + i) + "]";//$NON-NLS-1$//$NON-NLS-2$ diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/ExpressionTestApp.cc b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/ExpressionTestApp.cc index 54b4fec8425..88c10cd9eb9 100644 --- a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/ExpressionTestApp.cc +++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/ExpressionTestApp.cc @@ -293,6 +293,14 @@ int testCanWrite() { return 1; } +int testArrays() { + int array_simple[10]; + int array_int[24321]; + foo array_foo[1200]; + + return 1; +} + int main() { printf("Running ExpressionTest App\n"); @@ -317,6 +325,7 @@ int main() { testConcurrentUpdateOutOfScopeChildThenParent(); testUpdateOfPointer(); testCanWrite(); + testArrays(); // For bug 320277 BaseTest b; b.test(); 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 61934dbb880..ca68a7e736d 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 @@ -26,6 +26,7 @@ import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionChangedDMEvent; import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMAddress; 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.IIndexedPartitionDMContext; import org.eclipse.cdt.dsf.debug.service.IExpressions3.IExpressionDMDataExtension; import org.eclipse.cdt.dsf.debug.service.IFormattedValues; import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContext; @@ -320,37 +321,10 @@ public class MIExpressionsTest extends BaseTestCase { 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() { - @Override - 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()); + getChildrenCount(exprDmc, 5); } /** @@ -3263,8 +3237,14 @@ public class MIExpressionsTest extends BaseTestCase { getExprChangedCount() == 0); } + private IExpressionDMContext[] getChildren(IExpressionDMContext parentDmc, String[] expectedValues) throws Throwable { + return getChildren(parentDmc, -1, -1, expectedValues ); + } + private IExpressionDMContext[] getChildren( - final IExpressionDMContext parentDmc, + final IExpressionDMContext parentDmc, + final int startIndex, + final int length, String[] expectedValues) throws Throwable { final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); @@ -3273,7 +3253,10 @@ public class MIExpressionsTest extends BaseTestCase { @Override public void run() { - fExpService.getSubExpressions(parentDmc, + fExpService.getSubExpressions( + parentDmc, + startIndex, + length, new DataRequestMonitor(fExpService.getExecutor(), null) { @Override protected void handleCompleted() { @@ -3311,4 +3294,130 @@ public class MIExpressionsTest extends BaseTestCase { return childDmcs; } + + /** + * This test verifies that large arrays are properly partitioned and + * the handling of "small" arrays is not affected. + */ + @Test + public void testArrays() throws Throwable { + MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("testArrays"); + + IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); + + // int array_simple[10]; + IExpressionDMContext arraySimpleExprDMC = SyncUtil.createExpression(frameDmc, "array_simple"); + + getChildrenCount(arraySimpleExprDMC, 10); + + // get all children + String[] expectedValues = new String[10]; + for (int i = 0; i < expectedValues.length; ++i) { + expectedValues[i] = String.format("array_simple[%d]", i); + } + IExpressionDMContext[] arraySimpleChildren = getChildren(arraySimpleExprDMC, expectedValues); + for (IExpressionDMContext ctx : arraySimpleChildren) + getChildren(ctx, new String[0]); + + // get some parts of the children array + getChildren(arraySimpleExprDMC, 3, 2, new String[] { "array_simple[3]", "array_simple[4]" }); + getChildren(arraySimpleExprDMC, 9, 3, new String[] { "array_simple[9]" }); + + // int array_int[24321]; + IExpressionDMContext arrayIntExprDMC = SyncUtil.createExpression(frameDmc, "array_int"); + getChildrenCount(arrayIntExprDMC, 3); + + // get top level partitions: [0-9999], [10000-19999], [20000-24321] + IExpressionDMContext[] arrayIntPartitions = + getChildren(arrayIntExprDMC, new String[] {"*((array_int)+0)@10000", "*((array_int)+10000)@10000", "*((array_int)+20000)@4321"}); + assertTrue(String.format("Invalid number of partition: expected 3 got %d", arrayIntPartitions.length), arrayIntPartitions.length == 3); + + // get children of the last partition: [20000-24321] + expectedValues = new String[44]; + for(int i = 0; i < expectedValues.length - 1; ++i) { + expectedValues[i] = String.format("*((array_int)+%d)@100", 20000 + i*100); + } + expectedValues[expectedValues.length - 1] = "*((array_int)+24300)@21"; + IExpressionDMContext[] arrayIntPartitions1 = getChildren(arrayIntPartitions[2], expectedValues); + expectedValues = new String[21]; + for(int i = 0; i < expectedValues.length; ++i) { + expectedValues[i] = String.format("array_int[%d]", 24300 + i); + } + getChildren(arrayIntPartitions1[arrayIntPartitions1.length - 1], expectedValues); + + // foo array_foo[1200]; + IExpressionDMContext arrayFooExprDMC = SyncUtil.createExpression(frameDmc, "array_foo"); + getChildrenCount(arrayFooExprDMC, 12); + expectedValues = new String[12]; + for (int i = 0; i < expectedValues.length; ++i) { + expectedValues[i] = String.format("*((array_foo)+%d)@%d", i*100, 100); + } + IExpressionDMContext[] arrayFooPartitions = getChildren(arrayFooExprDMC, expectedValues); + for (int i = 0; i < arrayFooPartitions.length; ++i) { + IExpressionDMContext ctx = arrayFooPartitions[i]; + assertTrue(String.format("Invalid DM context type: expected '%s' got '%s'", + IIndexedPartitionDMContext.class.getName(), ctx.getClass().getName()), + ctx instanceof IIndexedPartitionDMContext); + expectedValues = new String[100]; + for (int j = 0; j < expectedValues.length; ++j) { + expectedValues[j] = String.format("array_foo[%d]", i*100 + j); + } + IExpressionDMContext[] arrayFooChildren = getChildren(ctx, expectedValues); + for (IExpressionDMContext fooCtx : arrayFooChildren) { + getChildren(fooCtx, new String[] {"bar", "bar2", "a", "b", "c"}); + } + + // get parts of the children array + expectedValues = new String[] { String.format("array_foo[%d]", i*100 + 3), String.format("array_foo[%d]", i*100 + 4) }; + getChildren(ctx, 3, 2, expectedValues); + getChildren(ctx, 99, 3, new String[] { String.format("array_foo[%d]", i*100 + 99) }); + } + } + + private int getChildrenCount(final IExpressionDMContext parentDmc, final int expectedCount) throws Throwable { + + final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); + + fExpService.getExecutor().submit(new Runnable() { + @Override + public void run() { + + fExpService.getSubExpressionCount( + parentDmc, + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (isSuccess()) { + wait.setReturnInfo(getData()); + if (getData() != expectedCount) { + wait.waitFinished( + new Status( + IStatus.ERROR, + TestsPlugin.PLUGIN_ID, + String.format( + "Failed getting count for children. Got %d instead of %d.", + getData(), + expectedCount))); + } + else { + wait.waitFinished(getStatus()); + } + } + else { + wait.waitFinished(getStatus()); + } + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + + int count = ((Integer)wait.getReturnInfo()).intValue(); + + assertTrue(String.format("Expected %d but got %d", expectedCount, count), count == expectedCount); + + return count; + } } diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/DsfCastToTypeSupport.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/DsfCastToTypeSupport.java index e625c17d03f..458f1829e1c 100644 --- a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/DsfCastToTypeSupport.java +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/DsfCastToTypeSupport.java @@ -25,6 +25,7 @@ import org.eclipse.cdt.dsf.datamodel.DMContexts; import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionChangedDMEvent; 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.IIndexedPartitionDMContext; import org.eclipse.cdt.dsf.debug.service.IExpressions2; import org.eclipse.cdt.dsf.debug.service.IExpressions2.CastInfo; import org.eclipse.cdt.dsf.debug.service.IExpressions2.ICastedExpressionDMContext; @@ -90,6 +91,9 @@ public class DsfCastToTypeSupport { } private boolean isValid() { + if (exprDMC instanceof IIndexedPartitionDMContext) + return false; + TestExpressions2Query query = new TestExpressions2Query(); dmvmProvider.getSession().getExecutor().execute(query); diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableVMNode.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableVMNode.java index f5bc8e03568..9163bb86cc0 100644 --- a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableVMNode.java +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableVMNode.java @@ -37,6 +37,7 @@ import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMAddress; 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.IExpressionDMLocation; +import org.eclipse.cdt.dsf.debug.service.IExpressions.IIndexedPartitionDMContext; import org.eclipse.cdt.dsf.debug.service.IExpressions2; import org.eclipse.cdt.dsf.debug.service.IExpressions3; import org.eclipse.cdt.dsf.debug.service.IExpressions3.IExpressionDMDataExtension; @@ -135,6 +136,11 @@ public class VariableVMNode extends AbstractExpressionVMNode */ public static final String PROP_VARIABLE_ADDRESS_CHANGED = ICachingVMProvider.PROP_IS_CHANGED_PREFIX + PROP_VARIABLE_ADDRESS; + /** + * 'PROP_VARIABLE_BASIC_TYPE' property value for indexed partitions + */ + private static final String INDEXED_PARTITION_TYPE = "indexed_partition_type"; //$NON-NLS-1$ + private final SyncVariableDataAccess fSyncVariableDataAccess; /** @@ -330,6 +336,16 @@ public class VariableVMNode extends AbstractExpressionVMNode }; }; + public final static LabelImage PARTITION_LABEL_IMAGE = new LabelImage(CDebugImages.DESC_OBJS_ARRAY_PARTITION) { + { setPropertyNames(new String[] { PROP_VARIABLE_BASIC_TYPE }); } + + @Override + public boolean isEnabled(IStatus status, java.util.Map properties) { + String type = (String)properties.get(PROP_VARIABLE_BASIC_TYPE); + return INDEXED_PARTITION_TYPE.equals(type); + }; + }; + protected IElementLabelProvider createLabelProvider() { // @@ -407,6 +423,7 @@ public class VariableVMNode extends AbstractExpressionVMNode new String[] { PROP_NAME }), POINTER_LABEL_IMAGE, AGGREGATE_LABEL_IMAGE, + PARTITION_LABEL_IMAGE, SIMPLE_LABEL_IMAGE, new StaleDataLabelForeground(), new VariableLabelFont(), @@ -422,6 +439,7 @@ public class VariableVMNode extends AbstractExpressionVMNode new String[] { PROP_ELEMENT_EXPRESSION }), POINTER_LABEL_IMAGE, AGGREGATE_LABEL_IMAGE, + PARTITION_LABEL_IMAGE, SIMPLE_LABEL_IMAGE, new StaleDataLabelForeground(), new VariableLabelFont(), @@ -770,10 +788,13 @@ public class VariableVMNode extends AbstractExpressionVMNode // In case of an error fill in the expression text in the name column and expressions columns. IExpressionDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IExpressions.IExpressionDMContext.class); if (dmc != null && dmc.getExpression() != null) { - update.setProperty(PROP_NAME, dmc.getExpression()); + String displayName = getExpressionDisplayName(dmc, dmc.getExpression()); + update.setProperty(PROP_NAME, displayName); if (expression == null) { - update.setProperty(PROP_ELEMENT_EXPRESSION, dmc.getExpression()); + update.setProperty(PROP_ELEMENT_EXPRESSION, displayName); } + if (dmc instanceof IIndexedPartitionDMContext) + update.setProperty(PROP_VARIABLE_BASIC_TYPE, INDEXED_PARTITION_TYPE); } update.setStatus(getStatus()); } @@ -814,11 +835,23 @@ public class VariableVMNode extends AbstractExpressionVMNode @ConfinedToDsfExecutor("getSession().getExecutor()") protected void fillExpressionDataProperties(IPropertiesUpdate update, IExpressionDMData data) { - update.setProperty(PROP_NAME, data.getName()); + IExpressionDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IExpressions.IExpressionDMContext.class); + String displayName = data.getName(); + if (dmc != null) { + displayName = getExpressionDisplayName(dmc, displayName); + } + update.setProperty(PROP_NAME, displayName); update.setProperty(PROP_VARIABLE_TYPE_NAME, data.getTypeName()); - IExpressionDMData.BasicType type = data.getBasicType(); - if (type != null) { - update.setProperty(PROP_VARIABLE_BASIC_TYPE, type.name()); + String typeValue = null; + if (dmc instanceof IIndexedPartitionDMContext) + typeValue = INDEXED_PARTITION_TYPE; + else { + IExpressionDMData.BasicType type = data.getBasicType(); + if (type != null) + typeValue = type.name(); + } + if (typeValue != null) { + update.setProperty(PROP_VARIABLE_BASIC_TYPE, typeValue); } // @@ -828,7 +861,7 @@ public class VariableVMNode extends AbstractExpressionVMNode // IExpression expression = (IExpression)DebugPlugin.getAdapter(update.getElement(), IExpression.class); if (expression == null) { - update.setProperty(AbstractExpressionVMNode.PROP_ELEMENT_EXPRESSION, data.getName()); + update.setProperty(AbstractExpressionVMNode.PROP_ELEMENT_EXPRESSION, displayName); } } @@ -1344,4 +1377,18 @@ public class VariableVMNode extends AbstractExpressionVMNode request.done(); } } + + /** + * Returns the label for the element with the given context. + */ + protected String getExpressionDisplayName(IExpressionDMContext dmc, String name) { + if (dmc instanceof IIndexedPartitionDMContext) { + IIndexedPartitionDMContext ipDmc = (IIndexedPartitionDMContext)dmc; + name = String.format( + "[%d...%d]", //$NON-NLS-1$ + ipDmc.getIndex(), + ipDmc.getIndex() + ipDmc.getLength() - 1); + } + return name; + } } diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IExpressions.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IExpressions.java index ba32cdcdd4d..fac33c4a85c 100644 --- a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IExpressions.java +++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IExpressions.java @@ -43,6 +43,30 @@ public interface IExpressions extends IFormattedValues { String getExpression(); } + /** + * To avoid SWT performance issues large arrays are divided into partitions. + * This interface represents the context of such a partition. + * + * @since 2.3 + */ + public interface IIndexedPartitionDMContext extends IExpressionDMContext { + + /** + * Returns the expression string of the parent array. + */ + public String getParentExpression(); + + /** + * Returns the index of the partition's first element in the parent array. + */ + public int getIndex(); + + /** + * Returns the number of array's elements in the partition. + */ + public int getLength(); + } + /** * The address and size of an expression. */ From 5f44a306c2c7b7a34f0948e9bb3f404554e21b18 Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Thu, 26 Jan 2012 13:52:33 -0500 Subject: [PATCH 3/4] Bug 365541: Cleanup IndexedPartitionDMC.toString() --- .../src/org/eclipse/cdt/dsf/mi/service/MIExpressions.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 9b518666d06..3b54e9d6bcf 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 @@ -485,7 +485,7 @@ public class MIExpressions extends AbstractDsfService implements IMIExpressions, @Override public String toString() { - return String.format( "%s[%d-%d]", baseToString(), Integer.valueOf( getIndex() ), Integer.valueOf( getIndex() + getLength() ) ); //$NON-NLS-1$ + return String.format( "%s.expr[%s][%d-%d]", baseToString(), getParentExpression(), getIndex(), getIndex() + getLength() - 1); //$NON-NLS-1$ } private static ExpressionInfo createExpressionInfo(ExpressionInfo parentInfo, int index, int length) { From ad2208cc7722dede84260c76563eaeade47c3efd Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Thu, 26 Jan 2012 14:22:22 -0500 Subject: [PATCH 4/4] Bug 365541: Extra JUnit tests for partitions. Also, don't look for all the children of array_foo as it requires over 14000 MI commands, and makes the test take over 30 seconds. --- .../data/launch/src/ExpressionTestApp.cc | 2 + .../dsf/gdb/tests/MIExpressionsTest.java | 159 +++++++++++++++++- 2 files changed, 156 insertions(+), 5 deletions(-) diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/ExpressionTestApp.cc b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/ExpressionTestApp.cc index 88c10cd9eb9..1fd97df0822 100644 --- a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/ExpressionTestApp.cc +++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/ExpressionTestApp.cc @@ -297,6 +297,8 @@ int testArrays() { int array_simple[10]; int array_int[24321]; foo array_foo[1200]; + int array_double_small[11][21]; + char array_double_large[111][210]; return 1; } 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 ca68a7e736d..c47754e1331 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 @@ -3237,10 +3237,57 @@ public class MIExpressionsTest extends BaseTestCase { getExprChangedCount() == 0); } - private IExpressionDMContext[] getChildren(IExpressionDMContext parentDmc, String[] expectedValues) throws Throwable { - return getChildren(parentDmc, -1, -1, expectedValues ); + // This method tests IExspressions.getSubExpressions(IExpressionDMC, DRM); + private IExpressionDMContext[] getChildren( + final IExpressionDMContext parentDmc, + String[] expectedValues) throws Throwable { + + final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); + + fExpService.getExecutor().submit(new Runnable() { + @Override + public void run() { + + fExpService.getSubExpressions(parentDmc, + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (isSuccess()) { + wait.setReturnInfo(getData()); + } + wait.waitFinished(getStatus()); + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + + IExpressionDMContext[] childDmcs = + (IExpressionDMContext[]) wait.getReturnInfo(); + + String[] childExpressions = new String[childDmcs.length]; + MIExpressionDMCAccessor[] childDmcsAccessor = new MIExpressionDMCAccessor[childDmcs.length]; + + // Convert to a MIExpressionDMCAccessor to be able to call getRelativeExpression + // Also convert to String[] to be able to use Arrays.toString() + for (int i = 0; i < childExpressions.length; i++) { + childDmcsAccessor[i] = new MIExpressionDMCAccessor(childDmcs[i]); + childExpressions[i] = childDmcsAccessor[i].getRelativeExpression(); + } + assertTrue("Expected " + Arrays.toString(expectedValues) + " but got " + Arrays.toString(childExpressions), + expectedValues.length == childExpressions.length); + + for (int i = 0; i < childDmcsAccessor.length; i++) { + assertTrue("Expected: " + expectedValues[i] + " got: " + childDmcsAccessor[i].getRelativeExpression(), + childDmcsAccessor[i].getRelativeExpression().equals(expectedValues[i])); + } + + return childDmcs; } + // This method tests IExpressions.getSubExpressions(IExpressionDMC, int, int, DRM); private IExpressionDMContext[] getChildren( final IExpressionDMContext parentDmc, final int startIndex, @@ -3363,9 +3410,9 @@ public class MIExpressionsTest extends BaseTestCase { expectedValues[j] = String.format("array_foo[%d]", i*100 + j); } IExpressionDMContext[] arrayFooChildren = getChildren(ctx, expectedValues); - for (IExpressionDMContext fooCtx : arrayFooChildren) { - getChildren(fooCtx, new String[] {"bar", "bar2", "a", "b", "c"}); - } + // check the children of a couple of children + getChildren(arrayFooChildren[0], new String[] {"bar", "bar2", "a", "b", "c"}); + getChildren(arrayFooChildren[80], new String[] {"bar", "bar2", "a", "b", "c"}); // get parts of the children array expectedValues = new String[] { String.format("array_foo[%d]", i*100 + 3), String.format("array_foo[%d]", i*100 + 4) }; @@ -3374,6 +3421,108 @@ public class MIExpressionsTest extends BaseTestCase { } } + /** + * This test verifies that large double arrays are properly partitioned + */ + @Test + public void testLargeDoubleArray() throws Throwable { + MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("testArrays"); + + IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); + + // char array_double_large[111][210] + IExpressionDMContext arrayDoubleLargeExprDMC = SyncUtil.createExpression(frameDmc, "array_double_large"); + + getChildrenCount(arrayDoubleLargeExprDMC, 2); + + // get top level partitions: [0-99], [100-110] + IExpressionDMContext[] arrayTopPartitions = + getChildren(arrayDoubleLargeExprDMC, new String[] {"*((array_double_large)+0)@100", "*((array_double_large)+100)@11"}); + assertTrue(String.format("Invalid number of partition: expected 2 got %d", arrayTopPartitions.length), arrayTopPartitions.length == 2); + + // get children child array_double_large[100-110] + IExpressionDMContext arrayDoubleLargeChildExprDMC = arrayTopPartitions[1]; + + getChildrenCount(arrayDoubleLargeChildExprDMC, 11); + + String[] expectedValues = new String[11]; + for(int i = 0; i < expectedValues.length; ++i) { + expectedValues[i] = String.format("array_double_large[%d]", 100 +i); + } + IExpressionDMContext[] arrayChild = getChildren(arrayDoubleLargeChildExprDMC, expectedValues); + + // get second level partitions: array_double_large[101][0-99], [100-199], [200-209] + IExpressionDMContext arrayDoubleLargeChildExprDMC2 = arrayChild[1]; + + getChildrenCount(arrayDoubleLargeChildExprDMC2, 3); + + IExpressionDMContext[] arraySecondLevelPartitions = + getChildren(arrayDoubleLargeChildExprDMC2, new String[] {"*((array_double_large[101])+0)@100", + "*((array_double_large[101])+100)@100", + "*((array_double_large[101])+200)@10"}); + assertTrue(String.format("Invalid number of partition: expected 3 got %d", arraySecondLevelPartitions.length), arraySecondLevelPartitions.length == 3); + + // get children of array_double_large[101][0-99] + IExpressionDMContext arrayDoubleLargeChildExprDMC3 = arraySecondLevelPartitions[0]; + + getChildrenCount(arrayDoubleLargeChildExprDMC3, 100); + + expectedValues = new String[100]; + for(int i = 0; i < expectedValues.length; ++i) { + expectedValues[i] = String.format("array_double_large[101][%d]", i); + } + IExpressionDMContext[] arrayChild2 = getChildren(arrayDoubleLargeChildExprDMC3, expectedValues); + + // No more children for array_double_large[101][*] + for (IExpressionDMContext ctx : arrayChild2) + getChildren(ctx, new String[0]); + + // get some parts of the children array + getChildren(arrayDoubleLargeChildExprDMC3, 3, 2, new String[] { "array_double_large[101][3]", "array_double_large[101][4]" }); + getChildren(arrayDoubleLargeChildExprDMC3, 98, 3, new String[] { "array_double_large[101][98]","array_double_large[101][99]" }); + } + + /** + * This test verifies that "small" double arrays is not affected by partitions. + */ + @Test + public void testSmallDoubleArray() throws Throwable { + MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("testArrays"); + + IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); + + // int array_double_small[11][21]; + IExpressionDMContext arrayDoubleSmallExprDMC = SyncUtil.createExpression(frameDmc, "array_double_small"); + + getChildrenCount(arrayDoubleSmallExprDMC, 11); + + // get all children of array_double_small + String[] expectedValues = new String[11]; + for (int i = 0; i < expectedValues.length; ++i) { + expectedValues[i] = String.format("array_double_small[%d]", i); + } + IExpressionDMContext[] arrayDoubleSmallChildren = getChildren(arrayDoubleSmallExprDMC, expectedValues); + + // get all children of array_double_small[3] + IExpressionDMContext arrayDoubleSmallChildExprDMC = arrayDoubleSmallChildren[3]; + + getChildrenCount(arrayDoubleSmallChildExprDMC, 21); + + expectedValues = new String[21]; + for (int i = 0; i < expectedValues.length; ++i) { + expectedValues[i] = arrayDoubleSmallChildExprDMC.getExpression() + "[" + i +"]"; + } + IExpressionDMContext[] arrayDoubleSmallGrandChildren = getChildren(arrayDoubleSmallChildExprDMC, expectedValues); + + // No more children for array_double_small[3][*] + for (IExpressionDMContext ctx : arrayDoubleSmallGrandChildren) + getChildren(ctx, new String[0]); + + // get some parts of the children array + getChildren(arrayDoubleSmallChildExprDMC, 3, 2, new String[] { "array_double_small[3][3]", "array_double_small[3][4]" }); + getChildren(arrayDoubleSmallChildExprDMC, 19, 3, new String[] { "array_double_small[3][19]","array_double_small[3][20]" }); + } + private int getChildrenCount(final IExpressionDMContext parentDmc, final int expectedCount) throws Throwable { final AsyncCompletionWaitor wait = new AsyncCompletionWaitor();