/******************************************************************************* * Copyright (c) 2000, 2008 QNX Software 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 * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * QNX Software Systems - Initial API and implementation * Ling Wang (Nokia) - 126262 *******************************************************************************/ package org.eclipse.cdt.debug.internal.core.model; import org.eclipse.cdt.debug.core.CDebugCorePlugin; import org.eclipse.cdt.debug.core.ICDebugConstants; import org.eclipse.cdt.debug.core.cdi.CDIException; import org.eclipse.cdt.debug.core.cdi.event.ICDIChangedEvent; import org.eclipse.cdt.debug.core.cdi.event.ICDIEvent; import org.eclipse.cdt.debug.core.cdi.event.ICDIResumedEvent; import org.eclipse.cdt.debug.core.cdi.model.ICDIExpression; import org.eclipse.cdt.debug.core.cdi.model.ICDIObject; import org.eclipse.cdt.debug.core.cdi.model.ICDITarget; import org.eclipse.cdt.debug.core.cdi.model.ICDIValue; import org.eclipse.cdt.debug.core.cdi.model.ICDIVariable; import org.eclipse.cdt.debug.core.cdi.model.ICDIVariableDescriptor; import org.eclipse.cdt.debug.core.cdi.model.type.ICDIArrayValue; import org.eclipse.cdt.debug.core.model.CVariableFormat; import org.eclipse.cdt.debug.core.model.ICStackFrame; import org.eclipse.cdt.debug.core.model.ICType; import org.eclipse.cdt.debug.core.model.ICValue; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.model.IExpression; import org.eclipse.debug.core.model.IValue; /** * Represents an expression in the CDI model. */ public class CExpression extends CLocalVariable implements IExpression { private String fText; private ICDIExpression fCDIExpression; private CStackFrame fStackFrame; private IValue fValue = CValueFactory.NULL_VALUE; private ICType fType; /** * Constructor for CExpression. */ public CExpression( CStackFrame frame, ICDIExpression cdiExpression, ICDIVariableDescriptor varObject ) { super( frame, varObject ); setFormat( CVariableFormat.getFormat( CDebugCorePlugin.getDefault().getPluginPreferences().getInt( ICDebugConstants.PREF_DEFAULT_EXPRESSION_FORMAT ) ) ); fText = cdiExpression.getExpressionText(); fCDIExpression = cdiExpression; fStackFrame = frame; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IExpression#getExpressionText() */ public String getExpressionText() { return fText; } /* (non-Javadoc) * @see org.eclipse.cdt.debug.core.cdi.event.ICDIEventListener#handleDebugEvents(org.eclipse.cdt.debug.core.cdi.event.ICDIEvent[]) */ public void handleDebugEvents( ICDIEvent[] events ) { for( int i = 0; i < events.length; i++ ) { ICDIEvent event = events[i]; ICDIObject source = event.getSource(); if ( event instanceof ICDIResumedEvent ) { if ( source != null ) { ICDITarget cdiTarget = source.getTarget(); if ( getCDITarget().equals( cdiTarget ) ) { setChanged( false ); resetValue(); } } } if ( event instanceof ICDIChangedEvent ) { // If a variable is changed (by user or program), // we should re-evaluate expressions. // Though it's better we check if the changed variable // is part of the expression, the effort required is not // worth the gain. // This is partial fix to bug 126262. It makes CDT behavior // in line with JDT. // The remaining problem (with both CDT & JDT) is: // Due to platform bug, the change will not show up in // Expression View until the view is redrawn (e.g. after stepping, // or when the view is uncovered from background). In other words, // if the Expression View is at the front (not covered) when the // variable is changed, the change won't be reflected in the view. if ( source instanceof ICDIVariable) { setChanged( false ); resetValue(); } } } super.handleDebugEvents( events ); } /* (non-Javadoc) * @see org.eclipse.cdt.debug.core.model.ICVariable#isEnabled() */ public boolean isEnabled() { return true; } /* (non-Javadoc) * @see org.eclipse.cdt.debug.core.model.ICVariable#canEnableDisable() */ public boolean canEnableDisable() { return true; } /* (non-Javadoc) * @see org.eclipse.cdt.debug.internal.core.model.CVariable#isBookkeepingEnabled() */ protected boolean isBookkeepingEnabled() { return false; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IExpression#getValue() */ public IValue getValue() { CStackFrame frame = (CStackFrame)getStackFrame(); try { return getValue( frame ); } catch( DebugException e ) { } return null; } protected synchronized IValue getValue( CStackFrame context ) throws DebugException { if ( fValue.equals( CValueFactory.NULL_VALUE ) ) { if ( context.isSuspended() ) { try { ICDIValue value = fCDIExpression.getValue( context.getCDIStackFrame() ); if ( value != null ) { if ( value instanceof ICDIArrayValue ) { ICType type = null; try { type = new CType( value.getType() ); } catch( CDIException e ) { // ignore and use default type } if ( type != null && type.isArray() ) { int[] dims = type.getArrayDimensions(); if ( dims.length > 0 && dims[0] > 0 ) fValue = CValueFactory.createIndexedValue( this, (ICDIArrayValue)value, 0, dims[0] ); } } else { fValue = CValueFactory.createValue( this, value ); } } } catch( CDIException e ) { targetRequestFailed( e.getMessage(), null ); } } } return fValue; } protected ICStackFrame getStackFrame() { return fStackFrame; } protected void resetValue() { if ( fValue instanceof AbstractCValue ) { ((AbstractCValue)fValue).reset(); // We can't just reset the value and toss the reference we've been // holding. Those things have a dispose() method and that needs to be // called when there is no further use for it (so debugger-engine // objects tied to the value can be freed). We return the AbstractCValue // as an IValue to the platform, which means the platform certainly // isn't going to dispose of it (there is no IValue.dispose method). // Notice that we call AbstractCValue.dispose in our dispose method // above. So, naturally, we need to do the same here. But then what is // the purpose of calling AbstractCValue.reset() if we just dispose of // the object, anyway? This whole thing seems a bit screwy. We should // either be holding on to the AbstractCValue and resetting it, or just // discarding it. The reset above doesn't hurt, but it sure seems // pointless. ((AbstractCValue) fValue).dispose(); } fValue = CValueFactory.NULL_VALUE; } /* (non-Javadoc) * @see org.eclipse.cdt.debug.internal.core.model.AbstractCVariable#getExpressionString() */ public String getExpressionString() throws DebugException { return getExpressionText(); } /* (non-Javadoc) * @see org.eclipse.cdt.debug.internal.core.model.AbstractCVariable#dispose() */ public void dispose() { if ( fCDIExpression != null ) { try { fCDIExpression.dispose(); fCDIExpression = null; } catch( CDIException e ) { } } if ( fValue instanceof AbstractCValue ) { ((AbstractCValue)fValue).dispose(); fValue = CValueFactory.NULL_VALUE; } internalDispose( true ); setDisposed( true ); } /* (non-Javadoc) * @see org.eclipse.cdt.debug.core.model.ICVariable#getType() */ public ICType getType() throws DebugException { if ( isDisposed() ) return null; if ( fType == null ) { synchronized( this ) { if ( fType == null ) { fType = ((ICValue)fValue).getType(); } } } return fType; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IVariable#getReferenceTypeName() */ public String getReferenceTypeName() throws DebugException { ICType type = getType(); return ( type != null ) ? type.getName() : ""; //$NON-NLS-1$ } }