blob: 01ffec58163120f39ea7bea91a83144e0894f0b3 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 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 v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.wst.jsdt.astview.views;
import java.util.ArrayList;
import org.eclipse.swt.graphics.Image;
import org.eclipse.wst.jsdt.astview.ASTViewPlugin;
import org.eclipse.wst.jsdt.core.Flags;
import org.eclipse.wst.jsdt.core.IJavaScriptElement;
import org.eclipse.wst.jsdt.core.dom.AST;
import org.eclipse.wst.jsdt.core.dom.CharacterLiteral;
import org.eclipse.wst.jsdt.core.dom.IBinding;
import org.eclipse.wst.jsdt.core.dom.IFunctionBinding;
import org.eclipse.wst.jsdt.core.dom.IPackageBinding;
import org.eclipse.wst.jsdt.core.dom.ITypeBinding;
import org.eclipse.wst.jsdt.core.dom.IVariableBinding;
import org.eclipse.wst.jsdt.core.dom.PrimitiveType;
import org.eclipse.wst.jsdt.core.dom.StringLiteral;
/**
*
*/
public class Binding extends ASTAttribute {
private final IBinding fBinding;
private final String fLabel;
private final Object fParent;
private final boolean fIsRelevant;
public Binding(Object parent, String label, IBinding binding, boolean isRelevant) {
fParent= parent;
fBinding= binding;
fLabel= label;
fIsRelevant= isRelevant;
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.astview.views.ASTAttribute#getParent()
*/
public Object getParent() {
return fParent;
}
public IBinding getBinding() {
return fBinding;
}
public boolean hasBindingProperties() {
return fBinding != null;
}
public boolean isRelevant() {
return fIsRelevant;
}
private static boolean isType(int typeKinds, int kind) {
return (typeKinds & kind) != 0;
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.astview.views.ASTAttribute#getChildren()
*/
public Object[] getChildren() {
if (fBinding != null) {
ArrayList res= new ArrayList();
res.add(new BindingProperty(this, "NAME", fBinding.getName(), true)); //$NON-NLS-1$
res.add(new BindingProperty(this, "KEY", fBinding.getKey(), true)); //$NON-NLS-1$
res.add(new BindingProperty(this, "IS RECOVERED", fBinding.isRecovered(), true)); //$NON-NLS-1$
switch (fBinding.getKind()) {
case IBinding.VARIABLE:
IVariableBinding variableBinding= (IVariableBinding) fBinding;
res.add(new BindingProperty(this, "IS FIELD", variableBinding.isField(), true)); //$NON-NLS-1$
res.add(new BindingProperty(this, "IS PARAMETER", variableBinding.isParameter(), true)); //$NON-NLS-1$
res.add(new BindingProperty(this, "VARIABLE ID", variableBinding.getVariableId(), true)); //$NON-NLS-1$
res.add(new BindingProperty(this, "MODIFIERS", Flags.toString(fBinding.getModifiers()), true)); //$NON-NLS-1$
res.add(new Binding(this, "TYPE", variableBinding.getType(), true)); //$NON-NLS-1$
res.add(new Binding(this, "DECLARING CLASS", variableBinding.getDeclaringClass(), true)); //$NON-NLS-1$
res.add(new Binding(this, "DECLARING METHOD", variableBinding.getDeclaringMethod(), true)); //$NON-NLS-1$
res.add(new Binding(this, "VARIABLE DECLARATION", variableBinding.getVariableDeclaration(), true)); //$NON-NLS-1$
res.add(new BindingProperty(this, "IS DEPRECATED", fBinding.isDeprecated(), true)); //$NON-NLS-1$
res.add(new BindingProperty(this, "CONSTANT VALUE", variableBinding.getConstantValue(), true)); //$NON-NLS-1$ //$NON-NLS-2$
break;
case IBinding.PACKAGE:
IPackageBinding packageBinding= (IPackageBinding) fBinding;
res.add(new BindingProperty(this, "IS UNNAMED", packageBinding.isUnnamed(), true)); //$NON-NLS-1$
res.add(new BindingProperty(this, "IS DEPRECATED", fBinding.isDeprecated(), true)); //$NON-NLS-1$
break;
case IBinding.TYPE:
ITypeBinding typeBinding= (ITypeBinding) fBinding;
res.add(new BindingProperty(this, "QUALIFIED NAME", typeBinding.getQualifiedName(), true)); //$NON-NLS-1$
int typeKind= getTypeKind(typeBinding);
boolean isRefType= isType(typeKind, REF_TYPE);
final boolean isNonPrimitive= ! isType(typeKind, PRIMITIVE_TYPE);
StringBuffer kinds= new StringBuffer("KIND:"); //$NON-NLS-1$
if (typeBinding.isArray()) kinds.append(" isArray"); //$NON-NLS-1$
if (typeBinding.isNullType()) kinds.append(" isNullType"); //$NON-NLS-1$
if (typeBinding.isPrimitive()) kinds.append(" isPrimitive"); //$NON-NLS-1$
// ref types
if (typeBinding.isClass()) kinds.append(" isClass"); //$NON-NLS-1$
res.add(new BindingProperty(this, kinds, true)); //$NON-NLS-1$
StringBuffer generics= new StringBuffer("GENERICS:"); //$NON-NLS-1$
if (!isType(typeKind, GENERIC | PARAMETRIZED)) {
generics.append(" (non-generic, non-parameterized)");
}
res.add(new BindingProperty(this, generics, isRefType)); //$NON-NLS-1$
res.add(new Binding(this, "ELEMENT TYPE", typeBinding.getElementType(), isType(typeKind, ARRAY_TYPE))); //$NON-NLS-1$
res.add(new Binding(this, "COMPONENT TYPE", typeBinding.getComponentType(), isType(typeKind, ARRAY_TYPE))); //$NON-NLS-1$
res.add(new BindingProperty(this, "DIMENSIONS", typeBinding.getDimensions(), isType(typeKind, ARRAY_TYPE))); //$NON-NLS-1$
final String createArrayTypeLabel= "CREATE ARRAY TYPE (+1)";
try {
ITypeBinding arrayType= typeBinding.createArrayType(1);
res.add(new Binding(this, createArrayTypeLabel, arrayType, true));
} catch (RuntimeException e) {
String msg= e.getClass().getName() + ": " + e.getLocalizedMessage();
boolean isRelevant= ! typeBinding.getName().equals(PrimitiveType.VOID.toString()) && ! typeBinding.isRecovered();
if (isRelevant) {
res.add(new Error(this, createArrayTypeLabel + ": " + msg, e));
} else {
res.add(new BindingProperty(this, createArrayTypeLabel, msg, false));
}
}
StringBuffer origin= new StringBuffer("ORIGIN:"); //$NON-NLS-1$
if (typeBinding.isTopLevel()) origin.append(" isTopLevel"); //$NON-NLS-1$
if (typeBinding.isNested()) origin.append(" isNested"); //$NON-NLS-1$
if (typeBinding.isLocal()) origin.append(" isLocal"); //$NON-NLS-1$
if (typeBinding.isMember()) origin.append(" isMember"); //$NON-NLS-1$
if (typeBinding.isAnonymous()) origin.append(" isAnonymous"); //$NON-NLS-1$
res.add(new BindingProperty(this, origin, isRefType));
res.add(new BindingProperty(this, "IS FROM SOURCE", typeBinding.isFromSource(), isType(typeKind, REF_TYPE | VARIABLE_TYPE | CAPTURE_TYPE))); //$NON-NLS-1$
res.add(new Binding(this, "PACKAGE", typeBinding.getPackage(), isRefType)); //$NON-NLS-1$
res.add(new Binding(this, "DECLARING CLASS", typeBinding.getDeclaringClass(), isType(typeKind, REF_TYPE | VARIABLE_TYPE | CAPTURE_TYPE))); //$NON-NLS-1$
res.add(new Binding(this, "DECLARING METHOD", typeBinding.getDeclaringMethod(), isType(typeKind, REF_TYPE | VARIABLE_TYPE | CAPTURE_TYPE))); //$NON-NLS-1$
res.add(new BindingProperty(this, "MODIFIERS", Flags.toString(fBinding.getModifiers()), isRefType)); //$NON-NLS-1$
res.add(new BindingProperty(this, "BINARY NAME", typeBinding.getBinaryName(), true)); //$NON-NLS-1$
res.add(new Binding(this, "TYPE DECLARATION", typeBinding.getTypeDeclaration(), isNonPrimitive)); //$NON-NLS-1$
res.add(new Binding(this, "ERASURE", typeBinding.getErasure(), isNonPrimitive)); //$NON-NLS-1$
res.add(new Binding(this, "SUPERCLASS", typeBinding.getSuperclass(), isRefType)); //$NON-NLS-1$
res.add(new BindingProperty(this, "DECLARED TYPES", typeBinding.getDeclaredTypes(), isRefType)); //$NON-NLS-1$
res.add(new BindingProperty(this, "DECLARED FIELDS", typeBinding.getDeclaredFields(), isRefType)); //$NON-NLS-1$
res.add(new BindingProperty(this, "DECLARED METHODS", typeBinding.getDeclaredMethods(), isRefType)); //$NON-NLS-1$
res.add(new BindingProperty(this, "IS DEPRECATED", fBinding.isDeprecated(), isRefType)); //$NON-NLS-1$
break;
case IBinding.METHOD:
IFunctionBinding methodBinding= (IFunctionBinding) fBinding;
res.add(new BindingProperty(this, "IS CONSTRUCTOR", methodBinding.isConstructor(), true)); //$NON-NLS-1$
res.add(new BindingProperty(this, "IS DEFAULT CONSTRUCTOR", methodBinding.isDefaultConstructor(), true)); //$NON-NLS-1$
res.add(new Binding(this, "DECLARING CLASS", methodBinding.getDeclaringClass(), true)); //$NON-NLS-1$
res.add(new Binding(this, "RETURN TYPE", methodBinding.getReturnType(), true)); //$NON-NLS-1$
res.add(new BindingProperty(this, "MODIFIERS", Flags.toString(fBinding.getModifiers()), true)); //$NON-NLS-1$
res.add(new BindingProperty(this, "PARAMETER TYPES", methodBinding.getParameterTypes(), true)); //$NON-NLS-1$
res.add(new BindingProperty(this, "IS VARARGS", methodBinding.isVarargs(), true)); //$NON-NLS-1$
res.add(new Binding(this, "METHOD DECLARATION", methodBinding.getMethodDeclaration(), true)); //$NON-NLS-1$
res.add(new BindingProperty(this, "PARAMETER TYPES", methodBinding.getParameterTypes(), true)); //$NON-NLS-1$
res.add(new BindingProperty(this, "IS DEPRECATED", fBinding.isDeprecated(), true)); //$NON-NLS-1$
res.add(Binding.createValueAttribute(this, "DEFAULT VALUE", methodBinding.getDefaultValue()));
int parameterCount= methodBinding.getParameterTypes().length;
break;
}
try {
IJavaScriptElement javaElement= fBinding.getJavaElement();
res.add(new JavaElement(this, javaElement));
} catch (RuntimeException e) {
String label= ">java element: " + e.getClass().getName() + " for \"" + fBinding.getKey() + "\""; //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
res.add(new Error(this, label, e));
ASTViewPlugin.log("Exception thrown in IBinding#getJavaElement() for \"" + fBinding.getKey() + "\"", e);
}
return res.toArray();
}
return EMPTY;
}
private final static int ARRAY_TYPE= 1 << 0;
private final static int NULL_TYPE= 1 << 1;
private final static int VARIABLE_TYPE= 1 << 2;
private final static int WILDCARD_TYPE= 1 << 3;
private final static int CAPTURE_TYPE= 1 << 4;
private final static int PRIMITIVE_TYPE= 1 << 5;
private final static int REF_TYPE= 1 << 6;
private final static int GENERIC= 1 << 8;
private final static int PARAMETRIZED= 1 << 9;
private int getTypeKind(ITypeBinding typeBinding) {
if (typeBinding.isArray()) return ARRAY_TYPE;
if (typeBinding.isNullType()) return NULL_TYPE;
if (typeBinding.isPrimitive()) return PRIMITIVE_TYPE;
return REF_TYPE;
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.astview.views.ASTAttribute#getLabel()
*/
public String getLabel() {
StringBuffer buf= new StringBuffer(fLabel);
buf.append(": "); //$NON-NLS-1$
if (fBinding != null) {
switch (fBinding.getKind()) {
case IBinding.VARIABLE:
IVariableBinding variableBinding= (IVariableBinding) fBinding;
if (!variableBinding.isField()) {
buf.append(variableBinding.getName());
} else if (variableBinding.getDeclaringClass() == null) {
buf.append("array type"); //$NON-NLS-1$
} else {
buf.append(variableBinding.getDeclaringClass().getName());
buf.append('.');
buf.append(variableBinding.getName());
}
break;
case IBinding.PACKAGE:
IPackageBinding packageBinding= (IPackageBinding) fBinding;
buf.append(packageBinding.getName());
break;
case IBinding.TYPE:
ITypeBinding typeBinding= (ITypeBinding) fBinding;
buf.append(typeBinding.getQualifiedName());
break;
case IBinding.METHOD:
IFunctionBinding methodBinding= (IFunctionBinding) fBinding;
buf.append(methodBinding.getDeclaringClass().getName());
buf.append('.');
buf.append(methodBinding.getName());
buf.append('(');
ITypeBinding[] parameters= methodBinding.getParameterTypes();
for (int i= 0; i < parameters.length; i++) {
if (i > 0) {
buf.append(", "); //$NON-NLS-1$
}
ITypeBinding parameter= parameters[i];
buf.append(parameter.getName());
}
buf.append(')');
break;
}
} else {
buf.append("null"); //$NON-NLS-1$
}
return buf.toString();
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.astview.views.ASTAttribute#getImage()
*/
public Image getImage() {
return null;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
public String toString() {
return getLabel();
}
/*
* @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || !obj.getClass().equals(getClass())) {
return false;
}
Binding other= (Binding) obj;
if (fParent == null) {
if (other.fParent != null)
return false;
} else if (! fParent.equals(other.fParent)) {
return false;
}
if (fBinding == null) {
if (other.fBinding != null)
return false;
} else if (! fBinding.equals(other.fBinding)) {
return false;
}
return true;
}
/*
* @see java.lang.Object#hashCode()
*/
public int hashCode() {
int result= fParent != null ? fParent.hashCode() : 0;
result+= (fBinding != null && fBinding.getKey() != null ? fBinding.getKey().hashCode() : 0);
return result;
}
public static String getBindingLabel(IBinding binding) {
String label;
if (binding == null) {
label= ">binding"; //$NON-NLS-1$
} else {
switch (binding.getKind()) {
case IBinding.VARIABLE:
label= "> variable binding"; //$NON-NLS-1$
break;
case IBinding.TYPE:
label= "> type binding"; //$NON-NLS-1$
break;
case IBinding.METHOD:
label= "> method binding"; //$NON-NLS-1$
break;
case IBinding.PACKAGE:
label= "> package binding"; //$NON-NLS-1$
break;
default:
label= "> unknown binding"; //$NON-NLS-1$
}
}
return label;
}
/**
* Creates an {@link ASTAttribute} for a value from
* {@link IMemberValuePairBinding#getValue()} or from
* {@link IFunctionBinding#getDefaultValue()}.
*/
public static ASTAttribute createValueAttribute(ASTAttribute parent, String name, Object value) {
ASTAttribute res;
if (value instanceof IBinding) {
IBinding binding= (IBinding) value;
res= new Binding(parent, name + ": " + getBindingLabel(binding), binding, true);
} else if (value instanceof String) {
res= new GeneralAttribute(parent, name, getEscapedStringLiteral((String) value));
} else if (value instanceof Object[]) {
res= new GeneralAttribute(parent, name, (Object[]) value);
} else if (value instanceof ASTAttribute) {
res= (ASTAttribute) value;
} else {
res= new GeneralAttribute(parent, name, value);
}
return res;
}
public static String getEscapedStringLiteral(String stringValue) {
StringLiteral stringLiteral= AST.newAST(AST.JLS3).newStringLiteral();
stringLiteral.setLiteralValue(stringValue);
return stringLiteral.getEscapedValue();
}
public static String getEscapedCharLiteral(char charValue) {
CharacterLiteral charLiteral= AST.newAST(AST.JLS3).newCharacterLiteral();
charLiteral.setCharValue(charValue);
return charLiteral.getEscapedValue();
}
}