Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/org.eclipse.tcf.cdt.ui/src/org/eclipse/tcf/internal/cdt/ui/hover/TCFDebugTextHover.java')
-rw-r--r--plugins/org.eclipse.tcf.cdt.ui/src/org/eclipse/tcf/internal/cdt/ui/hover/TCFDebugTextHover.java211
1 files changed, 211 insertions, 0 deletions
diff --git a/plugins/org.eclipse.tcf.cdt.ui/src/org/eclipse/tcf/internal/cdt/ui/hover/TCFDebugTextHover.java b/plugins/org.eclipse.tcf.cdt.ui/src/org/eclipse/tcf/internal/cdt/ui/hover/TCFDebugTextHover.java
new file mode 100644
index 000000000..7ffb5c80b
--- /dev/null
+++ b/plugins/org.eclipse.tcf.cdt.ui/src/org/eclipse/tcf/internal/cdt/ui/hover/TCFDebugTextHover.java
@@ -0,0 +1,211 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Wind River Systems, Inc. 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.internal.tcf.cdt.ui.hover;
+
+import java.math.BigInteger;
+import java.util.Map;
+
+import org.eclipse.cdt.debug.ui.editors.AbstractDebugTextHover;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.jface.text.DefaultInformationControl;
+import org.eclipse.jface.text.IInformationControl;
+import org.eclipse.jface.text.IInformationControlCreator;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextHoverExtension2;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.tm.internal.tcf.debug.ui.model.TCFChildren;
+import org.eclipse.tm.internal.tcf.debug.ui.model.TCFChildrenStackTrace;
+import org.eclipse.tm.internal.tcf.debug.ui.model.TCFNode;
+import org.eclipse.tm.internal.tcf.debug.ui.model.TCFNodeExecContext;
+import org.eclipse.tm.internal.tcf.debug.ui.model.TCFNodeExpression;
+import org.eclipse.tm.internal.tcf.debug.ui.model.TCFNodeStackFrame;
+import org.eclipse.tm.tcf.protocol.IChannel;
+import org.eclipse.tm.tcf.protocol.IToken;
+import org.eclipse.tm.tcf.services.IExpressions;
+import org.eclipse.tm.tcf.services.IExpressions.DoneCreate;
+import org.eclipse.tm.tcf.services.IExpressions.DoneDispose;
+import org.eclipse.tm.tcf.services.IExpressions.DoneEvaluate;
+import org.eclipse.tm.tcf.services.IExpressions.Expression;
+import org.eclipse.tm.tcf.services.IExpressions.Value;
+import org.eclipse.tm.tcf.util.TCFDataCache;
+import org.eclipse.tm.tcf.util.TCFTask;
+
+/**
+ * TCF implementation of debug expression hover for the C/C++ Editor.
+ */
+public class TCFDebugTextHover extends AbstractDebugTextHover implements ITextHoverExtension2 {
+
+ @Override
+ public IInformationControlCreator getHoverControlCreator() {
+ if (useExpressionExplorer()) {
+ return createExpressionInformationControlCreator();
+ }
+ else {
+ return new IInformationControlCreator() {
+ public IInformationControl createInformationControl(Shell parent) {
+ return new DefaultInformationControl(parent, false);
+ }
+ };
+ }
+ }
+
+ private IInformationControlCreator createExpressionInformationControlCreator() {
+ return new ExpressionInformationControlCreator();
+ }
+
+ protected boolean useExpressionExplorer() {
+ return true;
+ }
+
+ public Object getHoverInfo2(ITextViewer textViewer, IRegion hoverRegion) {
+ if (!useExpressionExplorer()) return getHoverInfo(textViewer, hoverRegion);
+ final TCFNodeStackFrame activeFrame = getActiveFrame();
+ if (activeFrame == null) return null;
+ final String text = getExpressionText(textViewer, hoverRegion);
+ if (text == null || text.length() == 0) return null;
+ try {
+ return new TCFTask<TCFNode>(activeFrame.getChannel()) {
+ public void run() {
+ TCFNode evalContext = activeFrame.isEmulated() ? activeFrame.getParent() : activeFrame;
+ TCFChildren cache = evalContext.getModel().getHoverExpressionCache(evalContext, text);
+ if (!cache.validate(this)) return;
+ Map<String,TCFNode> nodes = cache.getData();
+ if (nodes != null) {
+ for (TCFNode node : nodes.values()) {
+ TCFDataCache<IExpressions.Value> value = ((TCFNodeExpression)node).getValue();
+ if (!value.validate(this)) return;
+ if (value.getData() != null) {
+ done(node.getParent());
+ return;
+ }
+ }
+ }
+ done(null);
+ }
+ }.get();
+ }
+ catch (Exception x) {
+ // Problem in Eclipse 3.7:
+ // TextViewerHoverManager calls Thread.interrupt(),
+ // but it fails to handle InterruptedException.
+ // We have to catch and ignore the exception.
+ return null;
+ }
+ }
+
+ @Override
+ protected boolean canEvaluate() {
+ return getActiveFrame() != null;
+ }
+
+ private TCFNodeStackFrame getActiveFrame() {
+ IAdaptable context = getSelectionAdaptable();
+ if (context instanceof TCFNodeStackFrame) return (TCFNodeStackFrame) context;
+ if (context instanceof TCFNodeExecContext) {
+ try {
+ final TCFNodeExecContext exe = (TCFNodeExecContext) context;
+ return new TCFTask<TCFNodeStackFrame>(exe.getChannel()) {
+ public void run() {
+ TCFChildrenStackTrace stack = exe.getStackTrace();
+ if (!stack.validate(this)) return;
+ done(stack.getTopFrame());
+ }
+ }.get();
+ }
+ catch (Exception x) {
+ // Problem in Eclipse 3.7:
+ // TextViewerHoverManager calls Thread.interrupt(),
+ // but it fails to handle InterruptedException.
+ // We have to catch and ignore the exception.
+ return null;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ protected String evaluateExpression(final String expression) {
+ final TCFNodeStackFrame activeFrame = getActiveFrame();
+ if (activeFrame == null) return null;
+ final IChannel channel = activeFrame.getChannel();
+ return new TCFTask<String>(channel) {
+ public void run() {
+ final IExpressions exprSvc = channel.getRemoteService(IExpressions.class);
+ if (exprSvc != null) {
+ TCFNode evalContext = activeFrame.isEmulated() ? activeFrame.getParent() : activeFrame;
+ exprSvc.create(evalContext.getID(), null, expression, new DoneCreate() {
+ public void doneCreate(IToken token, Exception error, final Expression context) {
+ if (error == null) {
+ exprSvc.evaluate(context.getID(), new DoneEvaluate() {
+ public void doneEvaluate(IToken token, Exception error, Value value) {
+ if (error == null) {
+ done(getValueText(value));
+ } else {
+ done(null);
+ }
+ exprSvc.dispose(context.getID(), new DoneDispose() {
+ public void doneDispose(IToken token, Exception error) {
+ // no-op
+ }
+ });
+ }
+ });
+ } else {
+ done(null);
+ }
+ }
+ });
+ } else {
+ done(null);
+ }
+ }
+ }.getE();
+ }
+
+ private static String getValueText(Value value) {
+ BigInteger bigInteger = toBigInteger(value.getValue(), value.isBigEndian(), true);
+ switch(value.getTypeClass()) {
+ case integer:
+ return bigInteger.toString();
+ case real:
+ if (value.getValue().length <= 4) {
+ return String.valueOf(Float.intBitsToFloat(bigInteger.intValue()));
+ } else if (value.getValue().length <= 8) {
+ return String.valueOf(Double.longBitsToDouble(bigInteger.longValue()));
+ } else {
+ return "N/A";
+ }
+ default:
+ return "0x"+bigInteger.toString(16);
+ }
+ }
+
+ private static BigInteger toBigInteger(byte[] data, boolean big_endian, boolean sign_extension) {
+ byte[] temp = null;
+ if (sign_extension) {
+ temp = new byte[data.length];
+ }
+ else {
+ temp = new byte[data.length + 1];
+ temp[0] = 0; // Extra byte to avoid sign extension by BigInteger
+ }
+ if (big_endian) {
+ System.arraycopy(data, 0, temp, sign_extension ? 0 : 1, data.length);
+ }
+ else {
+ for (int i = 0; i < data.length; i++) {
+ temp[temp.length - i - 1] = data[i];
+ }
+ }
+ return new BigInteger(temp);
+ }
+}

Back to the top