/*******************************************************************************
* Copyright (c) 2009 IBM Corporation 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:
* IBM Corporation - initial API and implementation
* Zend Technologies
*******************************************************************************/
package org.eclipse.php.internal.debug.ui.hovers;
import static org.eclipse.php.internal.debug.core.model.IVariableFacet.Facet.*;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.model.IStackFrame;
import org.eclipse.debug.core.model.IVariable;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.dltk.annotations.Nullable;
import org.eclipse.dltk.core.IField;
import org.eclipse.dltk.core.ISourceModule;
import org.eclipse.dltk.core.ISourceRange;
import org.eclipse.dltk.core.IType;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.php.core.ast.nodes.*;
import org.eclipse.php.core.compiler.PHPFlags;
import org.eclipse.php.core.compiler.ast.nodes.NamespaceReference;
import org.eclipse.php.internal.core.corext.dom.NodeFinder;
import org.eclipse.php.internal.core.util.text.PHPTextSequenceUtilities;
import org.eclipse.php.internal.debug.core.PHPDebugPlugin;
import org.eclipse.php.internal.debug.core.model.VariablesUtil;
import org.eclipse.php.internal.debug.core.xdebug.dbgp.model.*;
import org.eclipse.php.internal.debug.core.xdebug.dbgp.protocol.DBGpResponse;
import org.eclipse.php.ui.editor.SharedASTProvider;
import org.w3c.dom.Node;
public class XDebugTextHover extends PHPDebugTextHover {
@Override
public Object getHoverInfo2(ITextViewer textViewer, IRegion hoverRegion) {
DBGpStackFrame frame = (DBGpStackFrame) getFrame();
if (frame == null)
return null;
DBGpVariable variable = null;
try {
ISourceModule sourceModule = getEditorInputModelElement();
ASTNode root = SharedASTProvider.getAST(sourceModule, SharedASTProvider.WAIT_NO, null);
if (root == null) {
ASTParser parser = ASTParser.newParser(sourceModule);
root = parser.createAST(null);
}
ASTNode node = NodeFinder.perform(root, hoverRegion.getOffset(), hoverRegion.getLength());
if (node instanceof Scalar) {
Scalar scalar = (Scalar) node;
if (node.getParent() instanceof ArrayAccess) {
ArrayAccess access = (ArrayAccess) node.getParent();
DBGpVariable var = getVariable(computeExpression(access.getName()));
String arrayAccessKey = scalar.getStringValue();
if (scalar.getScalarType() == Scalar.TYPE_STRING) {
arrayAccessKey = arrayAccessKey.replace("\"", ""); //$NON-NLS-1$ //$NON-NLS-2$
}
arrayAccessKey = "[" + arrayAccessKey + "]"; //$NON-NLS-1$ //$NON-NLS-2$
if (var != null) {
variable = fetchMember(var, arrayAccessKey);
}
} else if (!(scalar.getParent() instanceof Include) && scalar.getScalarType() == Scalar.TYPE_STRING) {
if (!(scalar.getStringValue().startsWith("\"") && scalar.getStringValue().endsWith("\""))) { //$NON-NLS-1$ //$NON-NLS-2$
variable = getVariable(scalar.getStringValue());
if (variable != null) {
variable.addFacets(KIND_CONSTANT);
variable.addFacets(MOD_PUBLIC);
}
}
}
} else if (node.getParent() instanceof Variable && node.getParent().getParent() instanceof FieldAccess) {
String nodeName = ((Identifier) node).getName();
String expression = computeExpression(((FieldAccess) node.getParent().getParent()).getDispatcher());
DBGpVariable var = getVariable(expression);
if (var != null) {
variable = fetchMember(var, nodeName);
}
} else if (node.getParent() instanceof StaticConstantAccess) {
String nodeName = ((Identifier) node).getName();
StaticConstantAccess staticAccess = (StaticConstantAccess) node.getParent();
String className = resolveTypeName((Identifier) staticAccess.getClassName());
if (className != null) {
String name = className + "::" + nodeName; //$NON-NLS-1$
variable = getVariable(name);
if (variable != null) {
if (nodeName.equals("class")) { //$NON-NLS-1$
variable.addFacets(VIRTUAL_CLASS);
} else {
variable.addFacets(KIND_CONSTANT);
variable.addFacets(MOD_PUBLIC);
}
}
}
} else if (node.getParent() instanceof StaticFieldAccess) {
Variable var = (Variable) node;
String nodeName = ((Identifier) var.getName()).getName();
StaticFieldAccess staticAccess = (StaticFieldAccess) node.getParent();
Identifier identifier = null;
if (staticAccess.getClassName() instanceof Identifier) {
identifier = (Identifier) staticAccess.getClassName();
} else if (staticAccess.getClassName() instanceof VariableBase) {
identifier = (Identifier) var.getName();
}
String className = resolveTypeName(identifier);
String name = className + "::$" + nodeName; //$NON-NLS-1$
variable = getVariable(name);
} else if (node.getParent() instanceof ConstantDeclaration) {
String nodeName = ((Identifier) node).getName();
IField field = (IField) sourceModule.getElementAt(node.getStart());
if (field.getParent() instanceof IType) {
IType type = (IType) field.getParent();
String typeName = type.getFullyQualifiedName(NamespaceReference.NAMESPACE_DELIMITER);
if (!PHPFlags.isNamespace(type.getFlags())) {
variable = getVariable(typeName + "::" + nodeName); //$NON-NLS-1$
} else {
variable = getVariable(typeName + NamespaceReference.NAMESPACE_DELIMITER + nodeName);
}
if (variable != null) {
variable.addFacets(KIND_CONSTANT);
variable.addFacets(MOD_PUBLIC);
}
}
} else if (node.getParent() instanceof SingleFieldDeclaration) {
IField field = (IField) sourceModule.getElementAt(node.getStart());
String typeName = "";
boolean isAnonymous = false;
if (field.getParent() instanceof IType) {
IType type = (IType) field.getParent();
typeName = type.getFullyQualifiedName(NamespaceReference.NAMESPACE_DELIMITER);
isAnonymous = PHPFlags.isAnonymous(type.getFlags());
}
Variable var = (Variable) node;
String nodeName = ((Identifier) var.getName()).getName();
if (!PHPFlags.isStatic(field.getFlags())) {
DBGpVariable varThis = getVariable("$this"); //$NON-NLS-1$
if (varThis != null) {
if (isAnonymous || typeName.equals(varThis.getValue().getValueString())) {
variable = fetchMember(varThis, nodeName);
}
}
} else {
variable = getVariable(typeName + "::$" + nodeName); //$NON-NLS-1$
}
} else {
// local variables
String variableName = null;
// ${a}
if (node instanceof Identifier && node.getParent() instanceof Variable
&& !((Variable) node.getParent()).isDollared()) {
variableName = "$" + ((Identifier) node).getName(); //$NON-NLS-1$
} else {
IDocument document = textViewer.getDocument();
if (document != null) {
// $$a
if (node instanceof ReflectionVariable) {
variableName = document.get(((ReflectionVariable) node).getName().getStart(),
((ReflectionVariable) node).getName().getLength());
} else {
// $a
variableName = document.get(hoverRegion.getOffset(), hoverRegion.getLength());
}
}
}
variable = (DBGpVariable) frame.findVariable(variableName);
}
} catch (Exception e) {
PHPDebugPlugin.log(e);
}
return variable;
}
protected IStackFrame getFrame() {
IAdaptable adaptable = DebugUITools.getDebugContext();
if (adaptable != null) {
return adaptable.getAdapter(DBGpStackFrame.class);
}
return null;
}
@Nullable
protected DBGpVariable getVariable(String expression) {
DBGpVariable variable = null;
DBGpStackFrame frame = (DBGpStackFrame) getFrame();
if (isStack(expression)) {
variable = getByProperty(frame, expression);
} else {
variable = getByEval(frame, expression);
}
return variable;
}
private void setContextFacets(IVariable variable) {
if (variable instanceof DBGpVariable) {
DBGpVariable dbgpVariable = (DBGpVariable) variable;
try {
String endName = dbgpVariable.getName();
if (VariablesUtil.isThis(endName))
dbgpVariable.addFacets(KIND_THIS);
else if (VariablesUtil.isSuperGlobal(endName))
dbgpVariable.addFacets(KIND_SUPER_GLOBAL);
else if (VariablesUtil.isClassIndicator(endName))
dbgpVariable.addFacets(VIRTUAL_CLASS);
else
dbgpVariable.addFacets(KIND_LOCAL);
} catch (DebugException e) {
// should not happen
}
}
}
/**
* Returns the variable value.
*
* @param expression
* The variable name
* @return
*/
protected DBGpVariable getByEval(DBGpStackFrame context, String expression) {
DBGpTarget debugTarget = (DBGpTarget) context.getDebugTarget();
Node resp = debugTarget.eval(expression);
if (resp == null) {
return null; // $NON-NLS-1$
}
return new DBGpEvalVariable(debugTarget, expression, resp);
}
protected DBGpVariable getByProperty(DBGpStackFrame context, String variable) {
DBGpTarget debugTarget = (DBGpTarget) context.getDebugTarget();
String stackLevel = context.getStackLevel();
Node resp = debugTarget.getProperty(variable, stackLevel, 0);
if (resp == null || DBGpResponse.REASON_ERROR.equals(resp.getNodeName())) {
// Check if it is not super global property
stackLevel = "-1"; //$NON-NLS-1$
resp = debugTarget.getProperty(variable, stackLevel, 0);
}
if (resp == null) {
return null; // $NON-NLS-1$
}
DBGpVariable var = new DBGpStackVariable(debugTarget, resp, Integer.valueOf(stackLevel));
setContextFacets(var);
return var;
}
private boolean isStack(String expression) {
if (expression.startsWith("$")) {//$NON-NLS-1$
ISourceRange enclosingIdentifier = PHPTextSequenceUtilities.getEnclosingIdentifier(expression, 0);
if (enclosingIdentifier != null && enclosingIdentifier.getLength() == expression.length() + 1) {
return true;
}
}
return false;
}
private DBGpVariable fetchMember(DBGpVariable variable, String memberName) {
try {
if (variable.getValue() == null || variable.getValue().getVariables() == null)
return null;
for (IVariable child : variable.getValue().getVariables()) {
if (child.getName().equals(memberName) && child instanceof DBGpVariable) {
return (DBGpVariable) child;
}
}
} catch (DebugException e) {
}
return null;
}
}