org.eclipse.jdt.internal.core.BinaryType.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.jdt.internal.core.BinaryType.java

Source

/*******************************************************************************
 * Copyright (c) 2000, 2017 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.jdt.internal.core;

import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;

import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.jdt.core.*;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.search.SearchEngine;
import org.eclipse.jdt.internal.codeassist.CompletionEngine;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.env.IBinaryAnnotation;
import org.eclipse.jdt.internal.compiler.env.IBinaryType;
import org.eclipse.jdt.internal.compiler.lookup.Binding;
import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
import org.eclipse.jdt.internal.core.JavaModelManager.PerProjectInfo;
import org.eclipse.jdt.internal.core.hierarchy.TypeHierarchy;
import org.eclipse.jdt.internal.core.util.MementoTokenizer;
import org.eclipse.jdt.internal.core.util.Messages;
import org.eclipse.jdt.internal.core.util.Util;

/**
 * Parent is an IClassFile.
 *
 * @see IType
 */

@SuppressWarnings({ "rawtypes", "unchecked" })
public class BinaryType extends BinaryMember implements IType, SuffixConstants {

    private static final IField[] NO_FIELDS = new IField[0];
    private static final IMethod[] NO_METHODS = new IMethod[0];
    private static final IType[] NO_TYPES = new IType[0];
    private static final IInitializer[] NO_INITIALIZERS = new IInitializer[0];
    public static final JavadocContents EMPTY_JAVADOC = new JavadocContents(null,
            org.eclipse.jdt.internal.compiler.util.Util.EMPTY_STRING);

    protected BinaryType(JavaElement parent, String name) {
        super(parent, name);
    }

    /*
     * Remove my cached children from the Java Model
     */
    @Override
    protected void closing(Object info) throws JavaModelException {
        ClassFileInfo cfi = getClassFileInfo();
        cfi.removeBinaryChildren();
    }

    /**
     * @see IType#codeComplete(char[], int, int, char[][], char[][], int[], boolean, ICompletionRequestor)
     * @deprecated
     */
    @Override
    public void codeComplete(char[] snippet, int insertion, int position, char[][] localVariableTypeNames,
            char[][] localVariableNames, int[] localVariableModifiers, boolean isStatic,
            ICompletionRequestor requestor) throws JavaModelException {
        codeComplete(snippet, insertion, position, localVariableTypeNames, localVariableNames,
                localVariableModifiers, isStatic, requestor, DefaultWorkingCopyOwner.PRIMARY);
    }

    /**
     * @see IType#codeComplete(char[], int, int, char[][], char[][], int[], boolean, ICompletionRequestor, WorkingCopyOwner)
     * @deprecated
     */
    @Override
    public void codeComplete(char[] snippet, int insertion, int position, char[][] localVariableTypeNames,
            char[][] localVariableNames, int[] localVariableModifiers, boolean isStatic,
            ICompletionRequestor requestor, WorkingCopyOwner owner) throws JavaModelException {
        if (requestor == null) {
            throw new IllegalArgumentException("Completion requestor cannot be null"); //$NON-NLS-1$
        }
        codeComplete(snippet, insertion, position, localVariableTypeNames, localVariableNames,
                localVariableModifiers, isStatic,
                new org.eclipse.jdt.internal.codeassist.CompletionRequestorWrapper(requestor), owner);
    }

    @Override
    public void codeComplete(char[] snippet, int insertion, int position, char[][] localVariableTypeNames,
            char[][] localVariableNames, int[] localVariableModifiers, boolean isStatic,
            CompletionRequestor requestor) throws JavaModelException {
        codeComplete(snippet, insertion, position, localVariableTypeNames, localVariableNames,
                localVariableModifiers, isStatic, requestor, DefaultWorkingCopyOwner.PRIMARY);
    }

    @Override
    public void codeComplete(char[] snippet, int insertion, int position, char[][] localVariableTypeNames,
            char[][] localVariableNames, int[] localVariableModifiers, boolean isStatic,
            CompletionRequestor requestor, IProgressMonitor monitor) throws JavaModelException {
        codeComplete(snippet, insertion, position, localVariableTypeNames, localVariableNames,
                localVariableModifiers, isStatic, requestor, DefaultWorkingCopyOwner.PRIMARY, monitor);
    }

    @Override
    public void codeComplete(char[] snippet, int insertion, int position, char[][] localVariableTypeNames,
            char[][] localVariableNames, int[] localVariableModifiers, boolean isStatic,
            CompletionRequestor requestor, WorkingCopyOwner owner) throws JavaModelException {
        codeComplete(snippet, insertion, position, localVariableTypeNames, localVariableNames,
                localVariableModifiers, isStatic, requestor, owner, null);
    }

    @Override
    public void codeComplete(char[] snippet, int insertion, int position, char[][] localVariableTypeNames,
            char[][] localVariableNames, int[] localVariableModifiers, boolean isStatic,
            CompletionRequestor requestor, WorkingCopyOwner owner, IProgressMonitor monitor)
            throws JavaModelException {
        if (requestor == null) {
            throw new IllegalArgumentException("Completion requestor cannot be null"); //$NON-NLS-1$
        }
        JavaProject project = (JavaProject) getJavaProject();
        SearchableEnvironment environment = project.newSearchableNameEnvironment(owner,
                requestor.isTestCodeExcluded());
        CompletionEngine engine = new CompletionEngine(environment, requestor, project.getOptions(true), project,
                owner, monitor);

        String source = getClassFile().getSource();
        if (source != null && insertion > -1 && insertion < source.length()) {
            // code complete

            char[] prefix = CharOperation.concat(source.substring(0, insertion).toCharArray(), new char[] { '{' });
            char[] suffix = CharOperation.concat(new char[] { '}' }, source.substring(insertion).toCharArray());
            char[] fakeSource = CharOperation.concat(prefix, snippet, suffix);

            BasicCompilationUnit cu = new BasicCompilationUnit(fakeSource, null, getElementName(), project); // use project to retrieve corresponding .java IFile

            engine.complete(cu, prefix.length + position, prefix.length, null/*extended context isn't computed*/);
        } else {
            engine.complete(this, snippet, position, localVariableTypeNames, localVariableNames,
                    localVariableModifiers, isStatic);
        }
        if (NameLookup.VERBOSE) {
            System.out.println(Thread.currentThread() + " TIME SPENT in NameLoopkup#seekTypesInSourcePackage: " //$NON-NLS-1$
                    + environment.nameLookup.timeSpentInSeekTypesInSourcePackage + "ms"); //$NON-NLS-1$
            System.out.println(Thread.currentThread() + " TIME SPENT in NameLoopkup#seekTypesInBinaryPackage: " //$NON-NLS-1$
                    + environment.nameLookup.timeSpentInSeekTypesInBinaryPackage + "ms"); //$NON-NLS-1$
        }
    }

    @Override
    public IField createField(String contents, IJavaElement sibling, boolean force, IProgressMonitor monitor)
            throws JavaModelException {
        throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.READ_ONLY, this));
    }

    @Override
    public IInitializer createInitializer(String contents, IJavaElement sibling, IProgressMonitor monitor)
            throws JavaModelException {
        throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.READ_ONLY, this));
    }

    @Override
    public IMethod createMethod(String contents, IJavaElement sibling, boolean force, IProgressMonitor monitor)
            throws JavaModelException {
        throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.READ_ONLY, this));
    }

    @Override
    public IType createType(String contents, IJavaElement sibling, boolean force, IProgressMonitor monitor)
            throws JavaModelException {
        throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.READ_ONLY, this));
    }

    @Override
    public boolean equals(Object o) {
        if (!(o instanceof BinaryType))
            return false;
        return super.equals(o);
    }

    @Override
    public IMethod[] findMethods(IMethod method) {
        try {
            return findMethods(method, getMethods());
        } catch (JavaModelException e) {
            // if type doesn't exist, no matching method can exist
            return null;
        }
    }

    @Override
    public IAnnotation[] getAnnotations() throws JavaModelException {
        IBinaryType info = (IBinaryType) getElementInfo();
        IBinaryAnnotation[] binaryAnnotations = info.getAnnotations();
        return getAnnotations(binaryAnnotations, info.getTagBits());
    }

    @Override
    public IJavaElement[] getChildren() throws JavaModelException {
        ClassFileInfo cfi = getClassFileInfo();
        return cfi.binaryChildren;
    }

    @Override
    public IJavaElement[] getChildrenForCategory(String category) throws JavaModelException {
        IJavaElement[] children = getChildren();
        int length = children.length;
        if (length == 0)
            return children;
        SourceMapper mapper = getSourceMapper();
        if (mapper != null) {
            // ensure the class file's buffer is open so that categories are computed
            getClassFile().getBuffer();

            HashMap categories = mapper.categories;
            IJavaElement[] result = new IJavaElement[length];
            int index = 0;
            if (categories != null) {
                for (int i = 0; i < length; i++) {
                    IJavaElement child = children[i];
                    String[] cats = (String[]) categories.get(child);
                    if (cats != null) {
                        for (int j = 0, length2 = cats.length; j < length2; j++) {
                            if (cats[j].equals(category)) {
                                result[index++] = child;
                                break;
                            }
                        }
                    }
                }
            }
            if (index < length)
                System.arraycopy(result, 0, result = new IJavaElement[index], 0, index);
            return result;
        }
        return NO_ELEMENTS;
    }

    protected ClassFileInfo getClassFileInfo() throws JavaModelException {
        return (ClassFileInfo) this.parent.getElementInfo();
    }

    @Override
    public IOrdinaryClassFile getClassFile() {
        return (IOrdinaryClassFile) super.getClassFile();
    }

    @Override
    public IType getDeclaringType() {
        IOrdinaryClassFile classFile = getClassFile();
        if (classFile.isOpen()) {
            try {
                char[] enclosingTypeName = ((IBinaryType) getElementInfo()).getEnclosingTypeName();
                if (enclosingTypeName == null) {
                    return null;
                }
                enclosingTypeName = ClassFile.unqualifiedName(enclosingTypeName);

                // workaround problem with class files compiled with javac 1.1.*
                // that return a non-null enclosing type name for local types defined in anonymous (e.g. A$1$B)
                if (classFile.getElementName().length() > enclosingTypeName.length + 1
                        && Character.isDigit(classFile.getElementName().charAt(enclosingTypeName.length + 1))) {
                    return null;
                }

                return getPackageFragment()
                        .getOrdinaryClassFile(new String(enclosingTypeName) + SUFFIX_STRING_class).getType();
            } catch (JavaModelException npe) {
                return null;
            }
        } else {
            // cannot access .class file without opening it
            // and getDeclaringType() is supposed to be a handle-only method,
            // so default to assuming $ is an enclosing type separator
            String classFileName = classFile.getElementName();
            int lastDollar = -1;
            for (int i = 0, length = classFileName.length(); i < length; i++) {
                char c = classFileName.charAt(i);
                if (Character.isDigit(c) && lastDollar == i - 1) {
                    // anonymous or local type
                    return null;
                } else if (c == '$') {
                    lastDollar = i;
                }
            }
            if (lastDollar == -1) {
                return null;
            } else {
                String enclosingName = classFileName.substring(0, lastDollar);
                String enclosingClassFileName = enclosingName + SUFFIX_STRING_class;
                return new BinaryType((JavaElement) getPackageFragment().getClassFile(enclosingClassFileName),
                        Util.localTypeName(enclosingName, enclosingName.lastIndexOf('$'), enclosingName.length()));
            }
        }
    }

    @Override
    public Object getElementInfo(IProgressMonitor monitor) throws JavaModelException {
        JavaModelManager manager = JavaModelManager.getJavaModelManager();
        Object info = manager.getInfo(this);
        if (info != null && info != JavaModelCache.NON_EXISTING_JAR_TYPE_INFO)
            return info;
        return openWhenClosed(createElementInfo(), false, monitor);
    }

    /*
     * @see IJavaElement
     */
    @Override
    public int getElementType() {
        return TYPE;
    }

    @Override
    public IField getField(String fieldName) {
        return new BinaryField(this, fieldName);
    }

    @Override
    public IField[] getFields() throws JavaModelException {
        ArrayList list = getChildrenOfType(FIELD);
        int size;
        if ((size = list.size()) == 0) {
            return NO_FIELDS;
        } else {
            IField[] array = new IField[size];
            list.toArray(array);
            return array;
        }
    }

    @Override
    public int getFlags() throws JavaModelException {
        IBinaryType info = (IBinaryType) getElementInfo();
        return info.getModifiers() & ~ClassFileConstants.AccSuper;
    }

    @Override
    public String getFullyQualifiedName() {
        return this.getFullyQualifiedName('$');
    }

    @Override
    public String getFullyQualifiedName(char enclosingTypeSeparator) {
        try {
            return getFullyQualifiedName(enclosingTypeSeparator, false/*don't show parameters*/);
        } catch (JavaModelException e) {
            // exception thrown only when showing parameters
            return null;
        }
    }

    @Override
    public String getFullyQualifiedParameterizedName() throws JavaModelException {
        return getFullyQualifiedName('.', true/*show parameters*/);
    }

    /*
     * @see JavaElement
     */
    @Override
    public IJavaElement getHandleFromMemento(String token, MementoTokenizer memento,
            WorkingCopyOwner workingCopyOwner) {
        switch (token.charAt(0)) {
        case JEM_COUNT:
            return getHandleUpdatingCountFromMemento(memento, workingCopyOwner);
        case JEM_FIELD:
            if (!memento.hasMoreTokens())
                return this;
            String fieldName = memento.nextToken();
            JavaElement field = (JavaElement) getField(fieldName);
            return field.getHandleFromMemento(memento, workingCopyOwner);
        case JEM_INITIALIZER:
            if (!memento.hasMoreTokens())
                return this;
            String count = memento.nextToken();
            JavaElement initializer = (JavaElement) getInitializer(Integer.parseInt(count));
            return initializer.getHandleFromMemento(memento, workingCopyOwner);
        case JEM_METHOD:
            if (!memento.hasMoreTokens())
                return this;
            String selector = memento.nextToken();
            ArrayList params = new ArrayList();
            nextParam: while (memento.hasMoreTokens()) {
                token = memento.nextToken();
                switch (token.charAt(0)) {
                case JEM_TYPE:
                case JEM_TYPE_PARAMETER:
                case JEM_ANNOTATION:
                    break nextParam;
                case JEM_METHOD:
                    if (!memento.hasMoreTokens())
                        return this;
                    String param = memento.nextToken();
                    StringBuffer buffer = new StringBuffer();
                    while (param.length() == 1 && Signature.C_ARRAY == param.charAt(0)) { // backward compatible with 3.0 mementos
                        buffer.append(Signature.C_ARRAY);
                        if (!memento.hasMoreTokens())
                            return this;
                        param = memento.nextToken();
                    }
                    params.add(buffer.toString() + param);
                    break;
                default:
                    break nextParam;
                }
            }
            String[] parameters = new String[params.size()];
            params.toArray(parameters);
            JavaElement method = (JavaElement) getMethod(selector, parameters);
            switch (token.charAt(0)) {
            case JEM_LAMBDA_EXPRESSION:
            case JEM_TYPE:
            case JEM_TYPE_PARAMETER:
            case JEM_LOCALVARIABLE:
            case JEM_ANNOTATION:
                return method.getHandleFromMemento(token, memento, workingCopyOwner);
            default:
                return method;
            }
        case JEM_TYPE:
            String typeName;
            if (memento.hasMoreTokens()) {
                typeName = memento.nextToken();
                char firstChar = typeName.charAt(0);
                if (firstChar == JEM_FIELD || firstChar == JEM_INITIALIZER || firstChar == JEM_METHOD
                        || firstChar == JEM_TYPE || firstChar == JEM_COUNT) {
                    token = typeName;
                    typeName = ""; //$NON-NLS-1$
                } else {
                    token = null;
                }
            } else {
                typeName = ""; //$NON-NLS-1$
                token = null;
            }
            JavaElement type = (JavaElement) getType(typeName);
            if (token == null) {
                return type.getHandleFromMemento(memento, workingCopyOwner);
            } else {
                return type.getHandleFromMemento(token, memento, workingCopyOwner);
            }
        case JEM_TYPE_PARAMETER:
            if (!memento.hasMoreTokens())
                return this;
            String typeParameterName = memento.nextToken();
            JavaElement typeParameter = new TypeParameter(this, typeParameterName);
            return typeParameter.getHandleFromMemento(memento, workingCopyOwner);
        case JEM_ANNOTATION:
            if (!memento.hasMoreTokens())
                return this;
            String annotationName = memento.nextToken();
            JavaElement annotation = new Annotation(this, annotationName);
            return annotation.getHandleFromMemento(memento, workingCopyOwner);
        }
        return null;
    }

    @Override
    public IInitializer getInitializer(int count) {
        return new Initializer(this, count);
    }

    @Override
    public IInitializer[] getInitializers() {
        return NO_INITIALIZERS;
    }

    @Override
    public String getKey(boolean forceOpen) throws JavaModelException {
        return getKey(this, forceOpen);
    }

    @Override
    public IMethod getMethod(String selector, String[] parameterTypeSignatures) {
        return new BinaryMethod(this, selector, parameterTypeSignatures);
    }

    @Override
    public IMethod[] getMethods() throws JavaModelException {
        ArrayList list = getChildrenOfType(METHOD);
        int size;
        if ((size = list.size()) == 0) {
            return NO_METHODS;
        } else {
            IMethod[] array = new IMethod[size];
            list.toArray(array);
            return array;
        }
    }

    @Override
    public IPackageFragment getPackageFragment() {
        IJavaElement parentElement = this.parent;
        while (parentElement != null) {
            if (parentElement.getElementType() == IJavaElement.PACKAGE_FRAGMENT) {
                return (IPackageFragment) parentElement;
            } else {
                parentElement = parentElement.getParent();
            }
        }
        Assert.isTrue(false); // should not happen
        return null;
    }

    /**
     * @see IType#getSuperclassTypeSignature()
     * @since 3.0
     */
    @Override
    public String getSuperclassTypeSignature() throws JavaModelException {
        IBinaryType info = (IBinaryType) getElementInfo();
        char[] genericSignature = info.getGenericSignature();
        if (genericSignature != null) {
            int signatureLength = genericSignature.length;
            // skip type parameters
            int index = 0;
            if (genericSignature[0] == '<') {
                int count = 1;
                while (count > 0 && ++index < signatureLength) {
                    switch (genericSignature[index]) {
                    case '<':
                        count++;
                        break;
                    case '>':
                        count--;
                        break;
                    }
                }
                index++;
            }
            int start = index;
            index = org.eclipse.jdt.internal.compiler.util.Util.scanClassTypeSignature(genericSignature, start) + 1;
            char[] superclassSig = CharOperation.subarray(genericSignature, start, index);
            return new String(ClassFile.translatedName(superclassSig));
        } else {
            char[] superclassName = info.getSuperclassName();
            if (superclassName == null) {
                return null;
            }
            return Signature.createTypeSignature(ClassFile.translatedName(superclassName), true);
        }
    }

    public String getSourceFileName(IBinaryType info) {
        if (info == null) {
            try {
                info = (IBinaryType) getElementInfo();
            } catch (JavaModelException e) {
                // default to using the outer most declaring type name
                IType type = this;
                IType enclosingType = getDeclaringType();
                while (enclosingType != null) {
                    type = enclosingType;
                    enclosingType = type.getDeclaringType();
                }
                return type.getElementName() + Util.defaultJavaExtension();
            }
        }
        return sourceFileName(info);
    }

    @Override
    public String getSuperclassName() throws JavaModelException {
        IBinaryType info = (IBinaryType) getElementInfo();
        char[] superclassName = info.getSuperclassName();
        if (superclassName == null) {
            return null;
        }
        return new String(ClassFile.translatedName(superclassName));
    }

    @Override
    public String[] getSuperInterfaceNames() throws JavaModelException {
        IBinaryType info = (IBinaryType) getElementInfo();
        char[][] names = info.getInterfaceNames();
        int length;
        if (names == null || (length = names.length) == 0) {
            return CharOperation.NO_STRINGS;
        }
        names = ClassFile.translatedNames(names);
        String[] strings = new String[length];
        for (int i = 0; i < length; i++) {
            strings[i] = new String(names[i]);
        }
        return strings;
    }

    /**
     * @see IType#getSuperInterfaceTypeSignatures()
     * @since 3.0
     */
    @Override
    public String[] getSuperInterfaceTypeSignatures() throws JavaModelException {
        IBinaryType info = (IBinaryType) getElementInfo();
        char[] genericSignature = info.getGenericSignature();
        if (genericSignature != null) {
            ArrayList interfaces = new ArrayList();
            int signatureLength = genericSignature.length;
            // skip type parameters
            int index = 0;
            if (genericSignature[0] == '<') {
                int count = 1;
                while (count > 0 && ++index < signatureLength) {
                    switch (genericSignature[index]) {
                    case '<':
                        count++;
                        break;
                    case '>':
                        count--;
                        break;
                    }
                }
                index++;
            }
            // skip superclass
            index = org.eclipse.jdt.internal.compiler.util.Util.scanClassTypeSignature(genericSignature, index) + 1;
            while (index < signatureLength) {
                int start = index;
                index = org.eclipse.jdt.internal.compiler.util.Util.scanClassTypeSignature(genericSignature, start)
                        + 1;
                char[] interfaceSig = CharOperation.subarray(genericSignature, start, index);
                interfaces.add(new String(ClassFile.translatedName(interfaceSig)));
            }
            int size = interfaces.size();
            String[] result = new String[size];
            interfaces.toArray(result);
            return result;
        } else {
            char[][] names = info.getInterfaceNames();
            int length;
            if (names == null || (length = names.length) == 0) {
                return CharOperation.NO_STRINGS;
            }
            names = ClassFile.translatedNames(names);
            String[] strings = new String[length];
            for (int i = 0; i < length; i++) {
                strings[i] = Signature.createTypeSignature(names[i], true);
            }
            return strings;
        }
    }

    @Override
    public ITypeParameter[] getTypeParameters() throws JavaModelException {
        String[] typeParameterSignatures = getTypeParameterSignatures();
        int length = typeParameterSignatures.length;
        if (length == 0)
            return TypeParameter.NO_TYPE_PARAMETERS;
        ITypeParameter[] typeParameters = new ITypeParameter[length];
        for (int i = 0; i < typeParameterSignatures.length; i++) {
            String typeParameterName = Signature.getTypeVariable(typeParameterSignatures[i]);
            typeParameters[i] = new TypeParameter(this, typeParameterName);
        }
        return typeParameters;
    }

    /**
     * @see IType#getTypeParameterSignatures()
     * @since 3.0
     */
    @Override
    public String[] getTypeParameterSignatures() throws JavaModelException {
        IBinaryType info = (IBinaryType) getElementInfo();
        char[] genericSignature = info.getGenericSignature();
        if (genericSignature == null)
            return CharOperation.NO_STRINGS;

        char[] dotBaseSignature = CharOperation.replaceOnCopy(genericSignature, '/', '.');
        char[][] typeParams = Signature.getTypeParameters(dotBaseSignature);
        return CharOperation.toStrings(typeParams);
    }

    @Override
    public IType getType(String typeName) {
        IClassFile classFile = getPackageFragment()
                .getClassFile(getTypeQualifiedName() + "$" + typeName + SUFFIX_STRING_class); //$NON-NLS-1$
        return new BinaryType((JavaElement) classFile, typeName);
    }

    @Override
    public ITypeParameter getTypeParameter(String typeParameterName) {
        return new TypeParameter(this, typeParameterName);
    }

    @Override
    public String getTypeQualifiedName() {
        return this.getTypeQualifiedName('$');
    }

    @Override
    public String getTypeQualifiedName(char enclosingTypeSeparator) {
        try {
            return getTypeQualifiedName(enclosingTypeSeparator, false/*don't show parameters*/);
        } catch (JavaModelException e) {
            // exception thrown only when showing parameters
            return null;
        }
    }

    @Override
    public IType[] getTypes() throws JavaModelException {
        ArrayList list = getChildrenOfType(TYPE);
        int size;
        if ((size = list.size()) == 0) {
            return NO_TYPES;
        } else {
            IType[] array = new IType[size];
            list.toArray(array);
            return array;
        }
    }

    @Override
    public boolean isAnonymous() throws JavaModelException {
        IBinaryType info = (IBinaryType) getElementInfo();
        return info.isAnonymous();
    }

    @Override
    public boolean isClass() throws JavaModelException {
        IBinaryType info = (IBinaryType) getElementInfo();
        return TypeDeclaration.kind(info.getModifiers()) == TypeDeclaration.CLASS_DECL;

    }

    /**
     * @see IType#isEnum()
     * @since 3.0
     */
    @Override
    public boolean isEnum() throws JavaModelException {
        IBinaryType info = (IBinaryType) getElementInfo();
        return TypeDeclaration.kind(info.getModifiers()) == TypeDeclaration.ENUM_DECL;
    }

    @Override
    public boolean isInterface() throws JavaModelException {
        IBinaryType info = (IBinaryType) getElementInfo();
        switch (TypeDeclaration.kind(info.getModifiers())) {
        case TypeDeclaration.INTERFACE_DECL:
        case TypeDeclaration.ANNOTATION_TYPE_DECL: // annotation is interface too
            return true;
        }
        return false;
    }

    /**
     * @see IType#isAnnotation()
     * @since 3.0
     */
    @Override
    public boolean isAnnotation() throws JavaModelException {
        IBinaryType info = (IBinaryType) getElementInfo();
        return TypeDeclaration.kind(info.getModifiers()) == TypeDeclaration.ANNOTATION_TYPE_DECL;
    }

    @Override
    public boolean isLocal() throws JavaModelException {
        IBinaryType info = (IBinaryType) getElementInfo();
        return info.isLocal();
    }

    @Override
    public boolean isMember() throws JavaModelException {
        IBinaryType info = (IBinaryType) getElementInfo();
        return info.isMember();
    }

    @Override
    public boolean isResolved() {
        return false;
    }

    /*
     * @see IType
     */
    @Override
    public ITypeHierarchy loadTypeHierachy(InputStream input, IProgressMonitor monitor) throws JavaModelException {
        return loadTypeHierachy(input, DefaultWorkingCopyOwner.PRIMARY, monitor);
    }

    /*
     * @see IType
     */
    public ITypeHierarchy loadTypeHierachy(InputStream input, WorkingCopyOwner owner, IProgressMonitor monitor)
            throws JavaModelException {
        return TypeHierarchy.load(this, input, owner);
    }

    @Override
    public ITypeHierarchy newSupertypeHierarchy(IProgressMonitor monitor) throws JavaModelException {
        return this.newSupertypeHierarchy(DefaultWorkingCopyOwner.PRIMARY, monitor);
    }

    @Override
    public ITypeHierarchy newSupertypeHierarchy(ICompilationUnit[] workingCopies, IProgressMonitor monitor)
            throws JavaModelException {

        CreateTypeHierarchyOperation op = new CreateTypeHierarchyOperation(this, workingCopies,
                SearchEngine.createWorkspaceScope(), false);
        op.runOperation(monitor);
        return op.getResult();
    }

    /**
     * @param workingCopies the working copies that take precedence over their original compilation units
     * @param monitor the given progress monitor
     * @return a type hierarchy for this type containing this type and all of its supertypes
     * @exception JavaModelException if this element does not exist or if an
     *      exception occurs while accessing its corresponding resource.
     *
     * @see IType#newSupertypeHierarchy(IWorkingCopy[], IProgressMonitor)
     * @deprecated
     */
    @Override
    public ITypeHierarchy newSupertypeHierarchy(IWorkingCopy[] workingCopies, IProgressMonitor monitor)
            throws JavaModelException {

        ICompilationUnit[] copies;
        if (workingCopies == null) {
            copies = null;
        } else {
            int length = workingCopies.length;
            System.arraycopy(workingCopies, 0, copies = new ICompilationUnit[length], 0, length);
        }
        return newSupertypeHierarchy(copies, monitor);
    }

    @Override
    public ITypeHierarchy newSupertypeHierarchy(WorkingCopyOwner owner, IProgressMonitor monitor)
            throws JavaModelException {

        ICompilationUnit[] workingCopies = JavaModelManager.getJavaModelManager().getWorkingCopies(owner,
                true/*add primary working copies*/);
        CreateTypeHierarchyOperation op = new CreateTypeHierarchyOperation(this, workingCopies,
                SearchEngine.createWorkspaceScope(), false);
        op.runOperation(monitor);
        return op.getResult();
    }

    @Override
    public ITypeHierarchy newTypeHierarchy(IJavaProject project, IProgressMonitor monitor)
            throws JavaModelException {
        return newTypeHierarchy(project, DefaultWorkingCopyOwner.PRIMARY, monitor);
    }

    @Override
    public ITypeHierarchy newTypeHierarchy(IJavaProject project, WorkingCopyOwner owner, IProgressMonitor monitor)
            throws JavaModelException {
        if (project == null) {
            throw new IllegalArgumentException(Messages.hierarchy_nullProject);
        }
        ICompilationUnit[] workingCopies = JavaModelManager.getJavaModelManager().getWorkingCopies(owner,
                true/*add primary working copies*/);
        ICompilationUnit[] projectWCs = null;
        if (workingCopies != null) {
            int length = workingCopies.length;
            projectWCs = new ICompilationUnit[length];
            int index = 0;
            for (int i = 0; i < length; i++) {
                ICompilationUnit wc = workingCopies[i];
                if (project.equals(wc.getJavaProject())) {
                    projectWCs[index++] = wc;
                }
            }
            if (index != length) {
                System.arraycopy(projectWCs, 0, projectWCs = new ICompilationUnit[index], 0, index);
            }
        }
        CreateTypeHierarchyOperation op = new CreateTypeHierarchyOperation(this, projectWCs, project, true);
        op.runOperation(monitor);
        return op.getResult();
    }

    /**
     * @param monitor the given progress monitor
     * @exception JavaModelException if this element does not exist or if an
     *      exception occurs while accessing its corresponding resource.
     * @return a type hierarchy for this type containing
     *
     * @see IType#newTypeHierarchy(IProgressMonitor monitor)
     * @deprecated
     */
    @Override
    public ITypeHierarchy newTypeHierarchy(IProgressMonitor monitor) throws JavaModelException {
        // https://bugs.eclipse.org/bugs/show_bug.cgi?id=228845, consider any
        // changes that may exist on primary working copies.
        return newTypeHierarchy(DefaultWorkingCopyOwner.PRIMARY, monitor);
    }

    @Override
    public ITypeHierarchy newTypeHierarchy(ICompilationUnit[] workingCopies, IProgressMonitor monitor)
            throws JavaModelException {

        CreateTypeHierarchyOperation op = new CreateTypeHierarchyOperation(this, workingCopies,
                SearchEngine.createWorkspaceScope(), true);
        op.runOperation(monitor);
        return op.getResult();
    }

    /**
     * @see IType#newTypeHierarchy(IWorkingCopy[], IProgressMonitor)
     * @deprecated
     */
    @Override
    public ITypeHierarchy newTypeHierarchy(IWorkingCopy[] workingCopies, IProgressMonitor monitor)
            throws JavaModelException {

        ICompilationUnit[] copies;
        if (workingCopies == null) {
            copies = null;
        } else {
            int length = workingCopies.length;
            System.arraycopy(workingCopies, 0, copies = new ICompilationUnit[length], 0, length);
        }
        return newTypeHierarchy(copies, monitor);
    }

    @Override
    public ITypeHierarchy newTypeHierarchy(WorkingCopyOwner owner, IProgressMonitor monitor)
            throws JavaModelException {

        ICompilationUnit[] workingCopies = JavaModelManager.getJavaModelManager().getWorkingCopies(owner,
                true/*add primary working copies*/);
        CreateTypeHierarchyOperation op = new CreateTypeHierarchyOperation(this, workingCopies,
                SearchEngine.createWorkspaceScope(), true);
        op.runOperation(monitor);
        return op.getResult();
    }

    @Override
    public JavaElement resolved(Binding binding) {
        SourceRefElement resolvedHandle = new ResolvedBinaryType(this.parent, this.name,
                new String(binding.computeUniqueKey()));
        resolvedHandle.occurrenceCount = this.occurrenceCount;
        return resolvedHandle;
    }

    /*
     * Returns the source file name as defined in the given info.
     * If not present in the info, infers it from this type.
     */
    public String sourceFileName(IBinaryType info) {
        char[] sourceFileName = info.sourceFileName();
        if (sourceFileName == null) {
            /*
             * We assume that this type has been compiled from a file with its name
             * For example, A.class comes from A.java and p.A.class comes from a file A.java
             * in the folder p.
             */
            if (info.isMember()) {
                IType enclosingType = getDeclaringType();
                if (enclosingType == null)
                    return null; // play it safe
                while (enclosingType.getDeclaringType() != null) {
                    enclosingType = enclosingType.getDeclaringType();
                }
                return enclosingType.getElementName() + Util.defaultJavaExtension();
            } else if (info.isLocal() || info.isAnonymous()) {
                String typeQualifiedName = getTypeQualifiedName();
                int dollar = typeQualifiedName.indexOf('$');
                if (dollar == -1) {
                    // malformed inner type: name doesn't contain a dollar
                    return getElementName() + Util.defaultJavaExtension();
                }
                return typeQualifiedName.substring(0, dollar) + Util.defaultJavaExtension();
            } else {
                return getElementName() + Util.defaultJavaExtension();
            }
        } else {
            int index = CharOperation.lastIndexOf('/', sourceFileName);
            return new String(sourceFileName, index + 1, sourceFileName.length - index - 1);
        }
    }

    /*
     * @private Debugging purposes
     */
    @Override
    protected void toStringInfo(int tab, StringBuffer buffer, Object info, boolean showResolvedInfo) {
        buffer.append(tabString(tab));
        if (info == null) {
            toStringName(buffer);
            buffer.append(" (not open)"); //$NON-NLS-1$
        } else if (info == NO_INFO) {
            toStringName(buffer);
        } else {
            try {
                if (isAnnotation()) {
                    buffer.append("@interface "); //$NON-NLS-1$
                } else if (isEnum()) {
                    buffer.append("enum "); //$NON-NLS-1$
                } else if (isInterface()) {
                    buffer.append("interface "); //$NON-NLS-1$
                } else {
                    buffer.append("class "); //$NON-NLS-1$
                }
                toStringName(buffer);
            } catch (JavaModelException e) {
                buffer.append("<JavaModelException in toString of " + getElementName()); //$NON-NLS-1$
            }
        }
    }

    @Override
    protected void toStringName(StringBuffer buffer) {
        if (getElementName().length() > 0)
            super.toStringName(buffer);
        else
            buffer.append("<anonymous>"); //$NON-NLS-1$
    }

    @Override
    public String getAttachedJavadoc(IProgressMonitor monitor) throws JavaModelException {
        JavadocContents javadocContents = getJavadocContents(monitor);
        if (javadocContents == null)
            return null;
        return javadocContents.getTypeDoc();
    }

    public JavadocContents getJavadocContents(IProgressMonitor monitor) throws JavaModelException {
        PerProjectInfo projectInfo = JavaModelManager.getJavaModelManager()
                .getPerProjectInfoCheckExistence(getJavaProject().getProject());
        JavadocContents cachedJavadoc = null;
        synchronized (projectInfo.javadocCache) {
            cachedJavadoc = (JavadocContents) projectInfo.javadocCache.get(this);
        }

        if (cachedJavadoc != null && cachedJavadoc != EMPTY_JAVADOC) {
            return cachedJavadoc;
        }
        URL baseLocation = getJavadocBaseLocation();
        if (baseLocation == null) {
            return null;
        }
        StringBuffer pathBuffer = new StringBuffer(baseLocation.toExternalForm());

        if (!(pathBuffer.charAt(pathBuffer.length() - 1) == '/')) {
            pathBuffer.append('/');
        }
        IPackageFragment pack = getPackageFragment();
        String typeQualifiedName = null;
        if (isMember()) {
            IType currentType = this;
            StringBuffer typeName = new StringBuffer();
            while (currentType != null) {
                typeName.insert(0, currentType.getElementName());
                currentType = currentType.getDeclaringType();
                if (currentType != null) {
                    typeName.insert(0, '.');
                }
            }
            typeQualifiedName = typeName.toString();
        } else {
            typeQualifiedName = getElementName();
        }

        pathBuffer.append(pack.getElementName().replace('.', '/')).append('/').append(typeQualifiedName)
                .append(JavadocConstants.HTML_EXTENSION);
        if (monitor != null && monitor.isCanceled())
            throw new OperationCanceledException();
        final String contents = getURLContents(baseLocation, String.valueOf(pathBuffer));
        JavadocContents javadocContents = new JavadocContents(this, contents);
        synchronized (projectInfo.javadocCache) {
            projectInfo.javadocCache.put(this, javadocContents);
        }
        return javadocContents;
    }

    @Override
    public boolean isLambda() {
        return false;
    }
}