/*
* Copyright (c) 2013, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.dart.tools.ui;
import com.google.dart.engine.element.ClassElement;
import com.google.dart.engine.element.CompilationUnitElement;
import com.google.dart.engine.element.ConstructorElement;
import com.google.dart.engine.element.Element;
import com.google.dart.engine.element.ElementKind;
import com.google.dart.engine.element.ExecutableElement;
import com.google.dart.engine.element.FieldElement;
import com.google.dart.engine.element.FunctionElement;
import com.google.dart.engine.element.MethodElement;
import com.google.dart.engine.element.ParameterElement;
import com.google.dart.engine.type.InterfaceType;
import com.google.dart.tools.ui.internal.viewsupport.StorageLabelProvider;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IStorage;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.ui.model.IWorkbenchAdapter;
/**
* Provides helper methods to render names of Dart elements.
* <p>
* <b>NOTE:</b> this will replace {@link DartElementLabels}.
*/
public class NewDartElementLabels {
/**
* Field names contain the declared type (prepended) e.g. <code>int fHello</code>
*/
public final static long F_PRE_TYPE_SIGNATURE = 1L << 15;
/**
* Fields names are fully qualified. e.g. <code>java.lang.System.out</code>
*/
public final static long F_FULLY_QUALIFIED = 1L << 16;
/**
* Field names contain the declared type (appended) e.g. <code>fHello : int</code>
*/
public final static long F_APP_TYPE_SIGNATURE = 1L << 14;
/**
* Fields names are post qualified. e.g. <code>out - java.lang.System</code>
*/
public final static long F_POST_QUALIFIED = 1L << 17;
/**
* Package names are compressed. e.g. <code>o*.e*.search</code>
*/
public final static long P_COMPRESSED = 1L << 37;
/**
* Specified to use the resolved information of a Type, IFunction or IField. See
* {@link Type#isResolved()}. If resolved information is available, types will be rendered with
* type parameters of the instantiated type. Resolved method render with the parameter types of
* the method instance. <code>Vector<String>.get(String)</code>
*/
public final static long USE_RESOLVED = 1L << 48;
private final static long QUALIFIER_FLAGS = P_COMPRESSED | USE_RESOLVED;
/**
* Type names are fully qualified. e.g. <code>java.util.Map.MapEntry</code>
*/
public final static long T_FULLY_QUALIFIED = 1L << 18;
/**
* User-readable string for separating the return type (e.g. " : ").
*/
public final static String DECL_STRING = DartUIMessages.JavaElementLabels_declseparator_string;
/**
* User-readable string for separating post qualified names (e.g. " - ").
*/
public final static String CONCAT_STRING = DartUIMessages.JavaElementLabels_concat_string;
/**
* Method names contain return type (appended) e.g. <code>int foo</code>
*/
public final static long M_PRE_RETURNTYPE = 1L << 6;
/**
* Method names contain parameter types. e.g. <code>foo(int)</code>
*/
public final static long M_PARAMETER_TYPES = 1L << 0;
/**
* Method names contain parameter names. e.g. <code>foo(index)</code>
*/
public final static long M_PARAMETER_NAMES = 1L << 1;
/**
* User-readable string for separating list items (e.g. ", ").
*/
public final static String COMMA_STRING = DartUIMessages.JavaElementLabels_comma_string;
/**
* User-readable string for ellipsis ("...").
*/
public final static String ELLIPSIS_STRING = "..."; //$NON-NLS-1$
/**
* Method names contain return type (appended) e.g. <code>foo : int</code>
*/
public final static long M_APP_RETURNTYPE = 1L << 5;
/**
* Method names contain thrown exceptions. e.g. <code>foo throws IOException</code>
*/
public final static long M_EXCEPTIONS = 1L << 4;
/**
* Method names are fully qualified. e.g. <code>java.util.Vector.size</code>
*/
public final static long M_FULLY_QUALIFIED = 1L << 7;
/**
* Method names are post qualified. e.g. <code>size - java.util.Vector</code>
*/
public final static long M_POST_QUALIFIED = 1L << 8;
/**
* Returns the label for a Dart element with the given flags.
*
* @param element The element to render.
* @param flags The rendering flags.
* @return the label of the Dart element
*/
public static String getElementLabel(Element element, long flags) {
StringBuffer buf = new StringBuffer(60);
getElementLabel(element, flags, buf);
return buf.toString();
}
/**
* Returns the label for a Dart element with the given flags.
*
* @param element The element to render.
* @param flags The rendering flags.
* @param buf The buffer to append the resulting label to.
*/
public static void getElementLabel(Element element, long flags, StringBuffer buf) {
ElementKind kind = element.getKind();
switch (kind) {
case CONSTRUCTOR:
case METHOD:
getMethodLabel((ExecutableElement) element, flags, buf);
break;
case FIELD:
getFieldLabel((FieldElement) element, flags, buf);
break;
case FUNCTION:
getFunctionLabel((FunctionElement) element, flags, buf);
break;
case CLASS:
getClassLabel((ClassElement) element, buf);
break;
default:
buf.append(element.getDisplayName());
}
}
public static String getTextLabel(Object obj, long flags) {
if (obj instanceof Element) {
return getElementLabel((Element) obj, flags);
} else if (obj instanceof IResource) {
return ((IResource) obj).getName();
} else if (obj instanceof IStorage) {
StorageLabelProvider storageLabelProvider = new StorageLabelProvider();
String label = storageLabelProvider.getText(obj);
storageLabelProvider.dispose();
return label;
} else if (obj instanceof IAdaptable) {
IWorkbenchAdapter wbadapter = (IWorkbenchAdapter) ((IAdaptable) obj).getAdapter(IWorkbenchAdapter.class);
if (wbadapter != null) {
return wbadapter.getLabel(obj);
}
}
return ""; //$NON-NLS-1$
}
private static void getClassLabel(ClassElement cls, StringBuffer buf) {
String clsName = cls.getDisplayName();
if (clsName.length() == 0) { // anonymous
String supertypeName = cls.getSupertype().getDisplayName();
clsName = Messages.format(DartUIMessages.JavaElementLabels_anonym_type, supertypeName);
}
buf.append(clsName);
}
private static void getCommonFunctionLabelElements(ExecutableElement method, long flags,
StringBuffer buf) {
if (method instanceof MethodElement) {
MethodElement m = (MethodElement) method;
if (m.getKind() == ElementKind.GETTER) {
return;
}
}
buf.append('(');
if (getFlag(flags, M_PARAMETER_TYPES | M_PARAMETER_NAMES)) {
String[] types = null;
int nParams = 0;
boolean renderVarargs = false;
if (getFlag(flags, M_PARAMETER_TYPES)) {
types = getParameterTypeNames(method);
nParams = types.length;
}
String[] names = null;
if (getFlag(flags, M_PARAMETER_NAMES)) {
names = getParameterNames(method);
nParams = names.length;
if (types == null) {
nParams = names.length;
} else { // types != null
if (nParams != names.length) {
if (types.length > names.length) {
nParams = names.length;
String[] typesWithoutSyntheticParams = new String[nParams];
System.arraycopy(
types,
types.length - nParams,
typesWithoutSyntheticParams,
0,
nParams);
types = typesWithoutSyntheticParams;
} else {
names = null; // no names rendered
}
}
}
}
for (int i = 0; i < nParams; i++) {
if (i > 0) {
buf.append(COMMA_STRING);
}
if (types != null) {
String paramSig = types[i];
if (renderVarargs && i == nParams - 1) {
buf.append(paramSig);
buf.append(ELLIPSIS_STRING);
} else {
buf.append(paramSig);
}
}
if (names != null) {
if (types != null) {
buf.append(' ');
}
buf.append(names[i]);
}
}
} else {
if (getParameterTypeNames(method).length > 0) {
buf.append(ELLIPSIS_STRING);
}
}
buf.append(')');
}
private static void getCompilationUnitLabel(CompilationUnitElement cu, long flags,
StringBuffer buf) {
buf.append(cu.getDisplayName());
}
private static String getDisplayName(ExecutableElement elem, ClassElement declaringType) {
if (elem instanceof ConstructorElement) {
ConstructorElement ce = (ConstructorElement) elem;
String name = declaringType.getDisplayName();
String constructorName = ce.getDisplayName();
if (constructorName != null && constructorName.length() > 0) {
name = name + '.' + constructorName;
}
return name;
}
return elem.getDisplayName();
}
private static ClassElement getEnclosingElement(ExecutableElement elem) {
if (elem instanceof ConstructorElement) {
return ((ConstructorElement) elem).getEnclosingElement();
}
if (elem instanceof MethodElement) {
return ((MethodElement) elem).getEnclosingElement();
}
throw new IllegalArgumentException("Expected Constructor or Method but got: " + elem.getKind());
}
private static void getFieldLabel(FieldElement field, long flags, StringBuffer buf) {
String typeName = getTypeName(field);
if (getFlag(flags, F_PRE_TYPE_SIGNATURE)) {
if (typeName != null) {
buf.append(typeName);
buf.append(' ');
}
}
// Qualification
ClassElement declaringType = field.getAncestor(ClassElement.class);
if (getFlag(flags, F_FULLY_QUALIFIED)) {
if (declaringType != null) {
getTypeLabel(declaringType, T_FULLY_QUALIFIED | flags & QUALIFIER_FLAGS, buf);
} else {
getFileLabel(field, T_FULLY_QUALIFIED | flags & QUALIFIER_FLAGS, buf);
}
buf.append('.');
}
buf.append(field.getDisplayName());
if (getFlag(flags, F_APP_TYPE_SIGNATURE)) {
if (typeName != null) {
buf.append(DECL_STRING);
buf.append(typeName);
}
}
// Post qualification
if (getFlag(flags, F_POST_QUALIFIED)) {
buf.append(CONCAT_STRING);
if (declaringType != null) {
getTypeLabel(declaringType, T_FULLY_QUALIFIED | flags & QUALIFIER_FLAGS, buf);
} else {
getFileLabel(field, T_FULLY_QUALIFIED | flags & QUALIFIER_FLAGS, buf);
}
}
}
private static void getFileLabel(Element elem, long flags, StringBuffer buf) {
CompilationUnitElement compUnit = elem.getAncestor(CompilationUnitElement.class);
if (compUnit != null) {
getCompilationUnitLabel(compUnit, flags, buf);
}
}
private static final boolean getFlag(long flags, long flag) {
return (flags & flag) != 0;
}
private static void getFunctionLabel(FunctionElement function, long flags, StringBuffer buf) {
// Return type
if (getFlag(flags, M_PRE_RETURNTYPE)) {
buf.append(function.getType().getReturnType().getDisplayName());
buf.append(' ');
}
String name = function.getDisplayName();
if (name == null || name.length() == 0) {
buf.append("function");
} else {
buf.append(name);
}
getCommonFunctionLabelElements(function, flags, buf);
}
private static void getMethodLabel(ExecutableElement elem, long flags, StringBuffer buf) {
// return type
if (getFlag(flags, M_PRE_RETURNTYPE) && elem.getKind() != ElementKind.CONSTRUCTOR) {
buf.append(elem.getType().getReturnType().getDisplayName());
buf.append(' ');
}
// qualification
ClassElement declaringType = getEnclosingElement(elem);
if (getFlag(flags, M_FULLY_QUALIFIED)) {
if (declaringType != null && elem.getKind() != ElementKind.CONSTRUCTOR) {
getTypeLabel(declaringType, T_FULLY_QUALIFIED | flags & QUALIFIER_FLAGS, buf);
buf.append('.');
}
}
buf.append(getDisplayName(elem, declaringType));
getCommonFunctionLabelElements(elem, flags, buf);
if (getFlag(flags, M_EXCEPTIONS)) {
String[] types;
types = new String[0];
if (types.length > 0) {
buf.append(" throws "); //$NON-NLS-1$
for (int i = 0; i < types.length; i++) {
if (i > 0) {
buf.append(COMMA_STRING);
}
}
}
}
if (getFlag(flags, M_APP_RETURNTYPE) && elem.getKind() != ElementKind.CONSTRUCTOR) {
String returnTypeName = elem.getType().getReturnType().getDisplayName();
if (returnTypeName != null) {
buf.append(DECL_STRING);
buf.append(returnTypeName);
}
}
// post qualification
if (getFlag(flags, M_POST_QUALIFIED)) {
buf.append(CONCAT_STRING);
if (declaringType != null) {
getTypeLabel(declaringType, T_FULLY_QUALIFIED | flags & QUALIFIER_FLAGS, buf);
} else {
getFileLabel(elem, T_FULLY_QUALIFIED | flags & QUALIFIER_FLAGS, buf);
}
}
}
private static String[] getParameterNames(ExecutableElement function) {
ParameterElement[] parameters = function.getParameters();
String[] names = new String[parameters.length];
for (int i = 0; i < parameters.length; i++) {
names[i] = parameters[i].getDisplayName();
}
return names;
}
private static String[] getParameterTypeNames(ExecutableElement function) {
ParameterElement[] parameters = function.getParameters();
String[] names = new String[parameters.length];
com.google.dart.engine.type.Type type;
for (int i = 0; i < parameters.length; i++) {
type = parameters[i].getType();
names[i] = type == null ? "var" : type.getDisplayName();
}
return names;
}
private static String getSuperTypeName(ClassElement type) {
InterfaceType supertype = type.getSupertype();
if (supertype != null) {
return supertype.getDisplayName();
}
return null;
}
private static void getTypeLabel(ClassElement type, long flags, StringBuffer buf) {
String typeName = type.getDisplayName();
if (typeName.length() == 0) { // anonymous
String supertypeName = getSuperTypeName(type);
if (supertypeName != null) {
typeName = Messages.format(DartUIMessages.JavaElementLabels_anonym_type, supertypeName);
} else {
typeName = DartUIMessages.JavaElementLabels_anonym;
}
}
buf.append(typeName);
}
private static String getTypeName(FieldElement field) {
com.google.dart.engine.type.Type type = field.getType();
if (type != null) {
return type.getDisplayName();
}
return null;
}
}