org.eclipse.jst.jsf.common.ui.internal.utils.JavaModelUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.jst.jsf.common.ui.internal.utils.JavaModelUtil.java

Source

/*******************************************************************************
 * Copyright (c) 2006 Sybase, 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:
 *     Sybase, Inc. - initial API and implementation
 *******************************************************************************/
package org.eclipse.jst.jsf.common.ui.internal.utils;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.ClasspathContainerInitializer;
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.IClasspathContainer;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IImportDeclaration;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeHierarchy;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.compiler.CharOperation;

/**
 * Original code is from JDT Utility methods for the Java Model.
 */
public final class JavaModelUtil {

    /**
     * Finds a type by its qualified type name (dot separated).
     * 
     * @param jproject
     *            The java project to search in
     * @param fullyQualifiedName
     *            The fully qualified name (type name with enclosing type names
     *            and package (all separated by dots))
     * @return The type found, or null if not existing
     * @throws JavaModelException 
     */
    public static IType findType(IJavaProject jproject, String fullyQualifiedName) throws JavaModelException {
        // workaround for bug 22883
        IType type = jproject.findType(fullyQualifiedName);
        if (type != null) {
            return type;
        }
        IPackageFragmentRoot[] roots = jproject.getPackageFragmentRoots();
        for (int i = 0; i < roots.length; i++) {
            IPackageFragmentRoot root = roots[i];
            type = findType(root, fullyQualifiedName);
            if (type != null && type.exists()) {
                return type;
            }
        }
        return null;
    }

    /**
     * Returns <code>true</code> if the given package fragment root is
     * referenced. This means it is own by a different project but is referenced
     * by the root's parent. Returns <code>false</code> if the given root
     * doesn't have an underlying resource.
     * @param root 
     * @return true if root is referenced
     */
    public static boolean isReferenced(IPackageFragmentRoot root) {
        IResource resource = root.getResource();
        if (resource != null) {
            IProject jarProject = resource.getProject();
            IProject container = root.getJavaProject().getProject();
            return !container.equals(jarProject);
        }
        return false;
    }

    private static IType findType(IPackageFragmentRoot root, String fullyQualifiedName) throws JavaModelException {
        IJavaElement[] children = root.getChildren();
        for (int i = 0; i < children.length; i++) {
            IJavaElement element = children[i];
            if (element.getElementType() == IJavaElement.PACKAGE_FRAGMENT) {
                IPackageFragment pack = (IPackageFragment) element;
                if (!fullyQualifiedName.startsWith(pack.getElementName())) {
                    continue;
                }
                IType type = findType(pack, fullyQualifiedName);
                if (type != null && type.exists()) {
                    return type;
                }
            }
        }
        return null;
    }

    private static IType findType(IPackageFragment pack, String fullyQualifiedName) throws JavaModelException {
        ICompilationUnit[] cus = pack.getCompilationUnits();
        for (int i = 0; i < cus.length; i++) {
            ICompilationUnit unit = cus[i];
            IType type = findType(unit, fullyQualifiedName);
            if (type != null && type.exists()) {
                return type;
            }
        }
        return null;
    }

    private static IType findType(ICompilationUnit cu, String fullyQualifiedName) throws JavaModelException {
        IType[] types = cu.getAllTypes();
        for (int i = 0; i < types.length; i++) {
            IType type = types[i];
            if (getFullyQualifiedName(type).equals(fullyQualifiedName)) {
                return type;
            }
        }
        return null;
    }

    /**
     * Finds a type by package and type name.
     * 
     * @param jproject
     *            the java project to search in
     * @param pack
     *            The package name
     * @param typeQualifiedName
     *            the type qualified name (type name with enclosing type names
     *            (separated by dots))
     * @return the type found, or null if not existing
     * @throws JavaModelException 
     * @deprecated Use IJavaProject.findType(String, String) instead
     */
    public static IType findType(IJavaProject jproject, String pack, String typeQualifiedName)
            throws JavaModelException {
        return jproject.findType(pack, typeQualifiedName);
    }

    /**
     * Finds a type container by container name. The returned element will be of
     * type <code>IType</code> or a <code>IPackageFragment</code>.
     * <code>null</code> is returned if the type container could not be found.
     * 
     * @param jproject
     *            The Java project defining the context to search
     * @param typeContainerName
     *            A dot separarted name of the type container
     * @return the java element
     * @throws JavaModelException 
     * @see #getTypeContainerName(IType)
     */
    public static IJavaElement findTypeContainer(IJavaProject jproject, String typeContainerName)
            throws JavaModelException {
        // try to find it as type
        IJavaElement result = jproject.findType(typeContainerName);
        if (result == null) {
            // find it as package
            IPath path = new Path(typeContainerName.replace('.', '/'));
            result = jproject.findElement(path);
            if (!(result instanceof IPackageFragment)) {
                result = null;
            }

        }
        return result;
    }

    /**
     * Finds a type in a compilation unit. Typical usage is to find the
     * corresponding type in a working copy.
     * 
     * @param cu
     *            the compilation unit to search in
     * @param typeQualifiedName
     *            the type qualified name (type name with enclosing type names
     *            (separated by dots))
     * @return the type found, or null if not existing
     * @throws JavaModelException 
     */
    public static IType findTypeInCompilationUnit(ICompilationUnit cu, String typeQualifiedName)
            throws JavaModelException {
        IType[] types = cu.getAllTypes();
        for (int i = 0; i < types.length; i++) {
            String currName = getTypeQualifiedName(types[i]);
            if (typeQualifiedName.equals(currName)) {
                return types[i];
            }
        }
        return null;
    }

    /**
     * Finds a a member in a compilation unit. Typical usage is to find the
     * corresponding member in a working copy.
     * 
     * @param cu
     *            the compilation unit (eg. working copy) to search in
     * @param member
     *            the member (eg. from the original)
     * @return the member found, or null if not existing
     */
    public static IMember findMemberInCompilationUnit(ICompilationUnit cu, IMember member) {
        IJavaElement[] elements = cu.findElements(member);
        if (elements != null && elements.length > 0) {
            return (IMember) elements[0];
        }
        return null;
    }

    /**
     * Returns the element of the given compilation unit which is "equal" to the
     * given element. Note that the given element usually has a parent different
     * from the given compilation unit.
     * 
     * @param cu
     *            the cu to search in
     * @param element
     *            the element to look for
     * @return an element of the given cu "equal" to the given element
     */
    public static IJavaElement findInCompilationUnit(ICompilationUnit cu, IJavaElement element) {
        IJavaElement[] elements = cu.findElements(element);
        if (elements != null && elements.length > 0) {
            return elements[0];
        }
        return null;
    }

    /**
     * Returns the qualified type name of the given type using '.' as
     * separators. This is a replace for IType.getTypeQualifiedName() which uses
     * '$' as separators. As '$' is also a valid character in an id this is
     * ambiguous. JavaCore PR: 1GCFUNT
     * @param type 
     * @return the type qualified name
     */
    public static String getTypeQualifiedName(IType type) {
        return type.getTypeQualifiedName('.');
    }

    /**
     * Returns the fully qualified name of the given type using '.' as
     * separators. This is a replace for IType.getFullyQualifiedTypeName which
     * uses '$' as separators. As '$' is also a valid character in an id this is
     * ambiguous. JavaCore PR: 1GCFUNT
     * @param type 
     * @return the fully qualified name using . as the separator
     */
    public static String getFullyQualifiedName(IType type) {
        return type.getFullyQualifiedName('.');
    }

    /**
     * Returns the fully qualified name of a type's container. (package name or
     * enclosing type name)
     * @param type 
     * @return the container name
     */
    public static String getTypeContainerName(IType type) {
        IType outerType = type.getDeclaringType();
        if (outerType != null) {
            return outerType.getFullyQualifiedName('.');
        }
        return type.getPackageFragment().getElementName();
    }

    /**
     * Concatenates two names. Uses a dot for separation. Both strings can be
     * empty or <code>null</code>.
     * @param name1 
     * @param name2 
     * @return name1 + name2
     */
    public static String concatenateName(String name1, String name2) {
        StringBuffer buf = new StringBuffer();
        if (name1 != null && name1.length() > 0) {
            buf.append(name1);
        }
        if (name2 != null && name2.length() > 0) {
            if (buf.length() > 0) {
                buf.append('.');
            }
            buf.append(name2);
        }
        return buf.toString();
    }

    /**
     * Concatenates two names. Uses a dot for separation. Both strings can be
     * empty or <code>null</code>.
     * @param name1 
     * @param name2 
     * @return name1 + name2
     */
    public static String concatenateName(char[] name1, char[] name2) {
        StringBuffer buf = new StringBuffer();
        if (name1 != null && name1.length > 0) {
            buf.append(name1);
        }
        if (name2 != null && name2.length > 0) {
            if (buf.length() > 0) {
                buf.append('.');
            }
            buf.append(name2);
        }
        return buf.toString();
    }

    /**
     * Evaluates if a member (possible from another package) is visible from
     * elements in a package.
     * 
     * @param member
     *            The member to test the visibility for
     * @param pack
     *            The package in focus
     * @return true if visible
     * @throws JavaModelException 
     */
    public static boolean isVisible(IMember member, IPackageFragment pack) throws JavaModelException {

        int type = member.getElementType();
        if (type == IJavaElement.INITIALIZER
                || (type == IJavaElement.METHOD && member.getElementName().startsWith("<"))) { //$NON-NLS-1$
            //$NON-NLS-1$
            return false;
        }

        int otherflags = member.getFlags();
        IType declaringType = member.getDeclaringType();
        if (Flags.isPublic(otherflags) || (declaringType != null && declaringType.isInterface())) {
            return true;
        } else if (Flags.isPrivate(otherflags)) {
            return false;
        }

        IPackageFragment otherpack = (IPackageFragment) findParentOfKind(member, IJavaElement.PACKAGE_FRAGMENT);
        return (pack != null && otherpack != null && isSamePackage(pack, otherpack));
    }

    /**
     * Evaluates if a member in the focus' element hierarchy is visible from
     * elements in a package.
     * 
     * @param member
     *            The member to test the visibility for
     * @param pack
     *            The package of the focus element focus
     * @return true if is visible in hiearchy
     * @throws JavaModelException 
     */
    public static boolean isVisibleInHierarchy(IMember member, IPackageFragment pack) throws JavaModelException {
        int type = member.getElementType();
        if (type == IJavaElement.INITIALIZER
                || (type == IJavaElement.METHOD && member.getElementName().startsWith("<"))) { //$NON-NLS-1$
            //$NON-NLS-1$
            return false;
        }

        int otherflags = member.getFlags();

        IType declaringType = member.getDeclaringType();
        if (Flags.isPublic(otherflags) || Flags.isProtected(otherflags)
                || (declaringType != null && declaringType.isInterface())) {
            return true;
        } else if (Flags.isPrivate(otherflags)) {
            return false;
        }

        IPackageFragment otherpack = (IPackageFragment) findParentOfKind(member, IJavaElement.PACKAGE_FRAGMENT);
        return (pack != null && pack.equals(otherpack));
    }

    /**
     * Returns the package fragment root of <code>IJavaElement</code>. If the
     * given element is already a package fragment root, the element itself is
     * returned.
     * @param element 
     * @return the package fragment root
     */
    public static IPackageFragmentRoot getPackageFragmentRoot(IJavaElement element) {
        return (IPackageFragmentRoot) element.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
    }

    /**
     * Returns the parent of the supplied java element that conforms to the
     * given parent type or <code>null</code>, if such a parent doesn't exit.
     * 
     * @deprecated Use element.getParent().getAncestor(kind);
     */
    private static IJavaElement findParentOfKind(IJavaElement element, int kind) {
        if (element != null && element.getParent() != null) {
            return element.getParent().getAncestor(kind);
        }
        return null;
    }

    /**
     * Finds a method in a type. This searches for a method with the same name
     * and signature. Parameter types are only compared by the simple name, no
     * resolving for the fully qualified type name is done. Constructors are
     * only compared by parameters, not the name.
     * 
     * @param name
     *            The name of the method to find
     * @param paramTypes
     *            The type signatures of the parameters e.g.
     *            <code>{"QString;","I"}</code>
     * @param isConstructor
     *            If the method is a constructor
     * @param type 
     * @return The first found method or <code>null</code>, if nothing found
     * @throws JavaModelException 
     */
    public static IMethod findMethod(String name, String[] paramTypes, boolean isConstructor, IType type)
            throws JavaModelException {
        return findMethod(name, paramTypes, isConstructor, type.getMethods());
    }

    /**
     * Finds a method by name. This searches for a method with a name and
     * signature. Parameter types are only compared by the simple name, no
     * resolving for the fully qualified type name is done. Constructors are
     * only compared by parameters, not the name.
     * 
     * @param name
     *            The name of the method to find
     * @param paramTypes
     *            The type signatures of the parameters e.g.
     *            <code>{"QString;","I"}</code>
     * @param isConstructor
     *            If the method is a constructor
     * @param methods
     *            The methods to search in
     * @return The found method or <code>null</code>, if nothing found
     * @throws JavaModelException 
     */
    public static IMethod findMethod(String name, String[] paramTypes, boolean isConstructor, IMethod[] methods)
            throws JavaModelException {
        for (int i = methods.length - 1; i >= 0; i--) {
            if (isSameMethodSignature(name, paramTypes, isConstructor, methods[i])) {
                return methods[i];
            }
        }
        return null;
    }

    /**
     * Finds a method declararion in a type's hierarchy. The search is top down,
     * so this returns the first declaration of the method in the hierarchy.
     * This searches for a method with a name and signature. Parameter types are
     * only compared by the simple name, no resolving for the fully qualified
     * type name is done. Constructors are only compared by parameters, not the
     * name.
     * @param hierarchy 
     * 
     * @param type
     *            Searches in this type's supertypes.
     * @param name
     *            The name of the method to find
     * @param paramTypes
     *            The type signatures of the parameters e.g.
     *            <code>{"QString;","I"}</code>
     * @param isConstructor
     *            If the method is a constructor
     * @return The first method found or null, if nothing found
     * @throws JavaModelException 
     */
    public static IMethod findMethodDeclarationInHierarchy(ITypeHierarchy hierarchy, IType type, String name,
            String[] paramTypes, boolean isConstructor) throws JavaModelException {
        IType[] superTypes = hierarchy.getAllSupertypes(type);
        for (int i = superTypes.length - 1; i >= 0; i--) {
            IMethod first = findMethod(name, paramTypes, isConstructor, superTypes[i]);
            if (first != null && !Flags.isPrivate(first.getFlags())) {
                // the order getAllSupertypes does make assumptions of the order
                // of inner elements -> search recursivly
                IMethod res = findMethodDeclarationInHierarchy(hierarchy, first.getDeclaringType(), name,
                        paramTypes, isConstructor);
                if (res != null) {
                    return res;
                }
                return first;
            }
        }
        return null;
    }

    /**
     * Finds a method implementation in a type's classhierarchy. The search is
     * bottom-up, so this returns the nearest overridden method. Does not find
     * methods in interfaces or abstract methods. This searches for a method
     * with a name and signature. Parameter types are only compared by the
     * simple name, no resolving for the fully qualified type name is done.
     * Constructors are only compared by parameters, not the name.
     * @param hierarchy 
     * 
     * @param type
     *            Type to search the superclasses
     * @param name
     *            The name of the method to find
     * @param paramTypes
     *            The type signatures of the parameters e.g.
     *            <code>{"QString;","I"}</code>
     * @param isConstructor
     *            If the method is a constructor
     * @return The first method found or null, if nothing found
     * @throws JavaModelException 
     */
    public static IMethod findMethodImplementationInHierarchy(ITypeHierarchy hierarchy, IType type, String name,
            String[] paramTypes, boolean isConstructor) throws JavaModelException {
        IType[] superTypes = hierarchy.getAllSuperclasses(type);
        for (int i = 0; i < superTypes.length; i++) {
            IMethod found = findMethod(name, paramTypes, isConstructor, superTypes[i]);
            if (found != null) {
                if (Flags.isAbstract(found.getFlags())) {
                    return null;
                }
                return found;
            }
        }
        return null;
    }

    private static IMethod findMethodInHierarchy(ITypeHierarchy hierarchy, IType type, String name,
            String[] paramTypes, boolean isConstructor) throws JavaModelException {
        IMethod method = findMethod(name, paramTypes, isConstructor, type);
        if (method != null) {
            return method;
        }
        IType superClass = hierarchy.getSuperclass(type);
        if (superClass != null) {
            IMethod res = findMethodInHierarchy(hierarchy, superClass, name, paramTypes, isConstructor);
            if (res != null) {
                return res;
            }
        }
        if (!isConstructor) {
            IType[] superInterfaces = hierarchy.getSuperInterfaces(type);
            for (int i = 0; i < superInterfaces.length; i++) {
                IMethod res = findMethodInHierarchy(hierarchy, superInterfaces[i], name, paramTypes, false);
                if (res != null) {
                    return res;
                }
            }
        }
        return method;
    }

    /**
     * Finds the method that is defines/declares the given method. The search is
     * bottom-up, so this returns the nearest defining/declaring method.
     * @param typeHierarchy 
     * @param type 
     * @param methodName 
     * @param paramTypes 
     * @param isConstructor 
     * 
     * @param testVisibility
     *            If true the result is tested on visibility. Null is returned
     *            if the method is not visible.
     * @return the method or null
     * @throws JavaModelException
     */
    public static IMethod findMethodDefininition(ITypeHierarchy typeHierarchy, IType type, String methodName,
            String[] paramTypes, boolean isConstructor, boolean testVisibility) throws JavaModelException {
        IType superClass = typeHierarchy.getSuperclass(type);
        if (superClass != null) {
            IMethod res = findMethodInHierarchy(typeHierarchy, superClass, methodName, paramTypes, isConstructor);
            if (res != null && !Flags.isPrivate(res.getFlags())) {
                if (!testVisibility || isVisibleInHierarchy(res, type.getPackageFragment())) {
                    return res;
                }
            }
        }
        if (!isConstructor) {
            IType[] interfaces = typeHierarchy.getSuperInterfaces(type);
            for (int i = 0; i < interfaces.length; i++) {
                IMethod res = findMethodInHierarchy(typeHierarchy, interfaces[i], methodName, paramTypes, false);
                if (res != null) {
                    return res; // methods from interfaces are always public and
                    // therefore visible
                }
            }
        }
        return null;
    }

    /**
     * Tests if a method equals to the given signature. Parameter types are only
     * compared by the simple name, no resolving for the fully qualified type
     * name is done. Constructors are only compared by parameters, not the name.
     * 
     * @param name
     *            Name of the method
     * @param paramTypes
     *            The type signatures of the parameters e.g.
     *            <code>{"QString;","I"}</code>
     * @param isConstructor
     *            Specifies if the method is a constructor
     * @param curr 
     * @return Returns <code>true</code> if the method has the given name and
     *         parameter types and constructor state.
     * @throws JavaModelException 
     */
    public static boolean isSameMethodSignature(String name, String[] paramTypes, boolean isConstructor,
            IMethod curr) throws JavaModelException {
        if (isConstructor || name.equals(curr.getElementName())) {
            if (isConstructor == curr.isConstructor()) {
                String[] currParamTypes = curr.getParameterTypes();
                if (paramTypes.length == currParamTypes.length) {
                    for (int i = 0; i < paramTypes.length; i++) {
                        String t1 = Signature.getSimpleName(Signature.toString(paramTypes[i]));
                        String t2 = Signature.getSimpleName(Signature.toString(currParamTypes[i]));
                        if (!t1.equals(t2)) {
                            return false;
                        }
                    }
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Tests if two <code>IPackageFragment</code>s represent the same logical
     * java package.
     * @param pack1 
     * @param pack2 
     * 
     * @return <code>true</code> if the package fragments' names are equal.
     */
    public static boolean isSamePackage(IPackageFragment pack1, IPackageFragment pack2) {
        return pack1.getElementName().equals(pack2.getElementName());
    }

    /**
     * Checks whether the given type has a valid main method or not.
     * @param type 
     * @return true if type has a main method
     * @throws JavaModelException 
     */
    public static boolean hasMainMethod(IType type) throws JavaModelException {
        IMethod[] methods = type.getMethods();
        for (int i = 0; i < methods.length; i++) {
            if (methods[i].isMainMethod()) {
                return true;
            }
        }
        return false;
    }

    /**
     * Checks if the field is boolean.
     * @param field 
     * @return true if the file is of primitive boolean type
     * @throws JavaModelException 
     */
    public static boolean isBoolean(IField field) throws JavaModelException {
        return field.getTypeSignature().equals(Signature.SIG_BOOLEAN);
    }

    /**
     * Tests if the given element is on the class path of its containing
     * project. Handles the case that the containing project isn't a Java
     * project.
     * @param element 
     * @return true if element in on the class path?
     */
    public static boolean isOnClasspath(IJavaElement element) {
        IJavaProject project = element.getJavaProject();
        if (!project.exists())
            return false;
        return project.isOnClasspath(element);
    }

    /**
     * Resolves a type name in the context of the declaring type.
     * 
     * @param refTypeSig
     *            the type name in signature notation (for example 'QVector')
     *            this can also be an array type, but dimensions will be
     *            ignored.
     * @param declaringType
     *            the context for resolving (type where the reference was made
     *            in)
     * @return returns the fully qualified type name or build-in-type name. if a
     *         unresoved type couldn't be resolved null is returned
     * @throws JavaModelException 
     */
    public static String getResolvedTypeName(String refTypeSig, IType declaringType) throws JavaModelException {
        int arrayCount = Signature.getArrayCount(refTypeSig);
        char type = refTypeSig.charAt(arrayCount);
        if (type == Signature.C_UNRESOLVED) {
            int semi = refTypeSig.indexOf(Signature.C_SEMICOLON, arrayCount + 1);
            if (semi == -1) {
                throw new IllegalArgumentException();
            }
            String name = refTypeSig.substring(arrayCount + 1, semi);

            String[][] resolvedNames = declaringType.resolveType(name);
            if (resolvedNames != null && resolvedNames.length > 0) {
                return JavaModelUtil.concatenateName(resolvedNames[0][0], resolvedNames[0][1]);
            }
            return null;
        }
        return Signature.toString(refTypeSig.substring(arrayCount));
    }

    /**
     * Returns if a CU can be edited.
     * @param cu 
     * @return true if cu is editable
     */
    public static boolean isEditable(ICompilationUnit cu) {
        IResource resource = toOriginal(cu).getResource();
        return (resource.exists() && !resource.getResourceAttributes().isReadOnly());
    }

    /**
     * Finds a qualified import for a type name.
     * @param cu 
     * @param simpleName 
     * @return the import declaration or null
     * @throws JavaModelException 
     */
    public static IImportDeclaration findImport(ICompilationUnit cu, String simpleName) throws JavaModelException {
        IImportDeclaration[] existing = cu.getImports();
        for (int i = 0; i < existing.length; i++) {
            String curr = existing[i].getElementName();
            if (curr.endsWith(simpleName)) {
                int dotPos = curr.length() - simpleName.length() - 1;
                if ((dotPos == -1) || (dotPos > 0 && curr.charAt(dotPos) == '.')) {
                    return existing[i];
                }
            }
        }
        return null;
    }

    /**
     * Returns the original if the given member. If the member is already an
     * original the input is returned. The returned member might not exist
     * @param member 
     * @return the original IMember
     */
    public static IMember toOriginal(IMember member) {
        if (member instanceof IMethod) {
            return toOriginalMethod((IMethod) member);
        }

        return (IMember) member.getPrimaryElement();
        /*
         * ICompilationUnit cu= member.getCompilationUnit(); if (cu != null &&
         * cu.isWorkingCopy()) return (IMember)cu.getOriginal(member); return
         * member;
         */
    }

    /*
     * XXX workaround for bug 18568
     * http://bugs.eclipse.org/bugs/show_bug.cgi?id=18568 to be removed once the
     * bug is fixed
     */
    private static IMethod toOriginalMethod(IMethod method) {
        ICompilationUnit cu = method.getCompilationUnit();
        if (cu == null || isPrimary(cu)) {
            return method;
        }
        try {
            // use the workaround only if needed
            if (!method.getElementName().equals(method.getDeclaringType().getElementName()))
                return (IMethod) method.getPrimaryElement();

            IType originalType = (IType) toOriginal(method.getDeclaringType());
            IMethod[] methods = originalType.findMethods(method);
            boolean isConstructor = method.isConstructor();
            for (int i = 0; i < methods.length; i++) {
                if (methods[i].isConstructor() == isConstructor)
                    return methods[i];
            }
            return null;
        } catch (JavaModelException e) {
            return null;
        }
    }

    // private static boolean PRIMARY_ONLY = false;

    /**
     * Returns the original cu if the given cu is a working copy. If the cu is
     * already an original the input cu is returned. The returned cu might not
     * exist
     * @param cu 
     * @return the original compiliation unit
     */
    public static ICompilationUnit toOriginal(ICompilationUnit cu) {
        // To stay compatible with old version returned null
        // if cu is null
        if (cu == null)
            return cu;
        return cu.getPrimary();
    }

    /**
     * Returns the original element if the given element is a working copy. If
     * the cu is already an original the input element is returned. The returned
     * element might not exist
     * @param element 
     * @return element's primary element
     */
    public static IJavaElement toOriginal(IJavaElement element) {
        return element.getPrimaryElement();
    }

    /**
     * Returns true if a cu is a primary cu (original or shared working copy)
     * @param cu 
     * @return true if cu  is primary
     */
    public static boolean isPrimary(ICompilationUnit cu) {
        return cu.getOwner() == null;
    }

    /**
     * http://bugs.eclipse.org/bugs/show_bug.cgi?id=19253
     * 
     * Reconciling happens in a separate thread. This can cause a situation
     * where the Java element gets disposed after an exists test has been done.
     * So we should not log not present exceptions when they happen in working
     * copies.
     * @param exception 
     * @return true if filter not present
     */
    public static boolean filterNotPresentException(CoreException exception) {
        if (!(exception instanceof JavaModelException)) {
            return true;
        }
        JavaModelException je = (JavaModelException) exception;
        if (!je.isDoesNotExist()) {
            return true;
        }
        IJavaElement[] elements = je.getJavaModelStatus().getElements();
        for (int i = 0; i < elements.length; i++) {
            IJavaElement element = elements[i];
            ICompilationUnit unit = (ICompilationUnit) element.getAncestor(IJavaElement.COMPILATION_UNIT);
            if (unit == null) {
                return true;
            }
            if (!unit.isWorkingCopy()) {
                return true;
            }
        }
        return false;
    }

    /**
     * @param type
     * @param pm
     * @return all supertypes of type
     * @throws JavaModelException
     */
    public static IType[] getAllSuperTypes(IType type, IProgressMonitor pm) throws JavaModelException {
        // workaround for 23656
        Set types = new HashSet(Arrays.asList(type.newSupertypeHierarchy(pm).getAllSupertypes(type)));
        IType objekt = type.getJavaProject().findType("java.lang.Object");//$NON-NLS-1$
        if (objekt != null) {
            types.add(objekt);
        }
        return (IType[]) types.toArray(new IType[types.size()]);
    }

    /**
     * @param resourcePath
     * @param exclusionPatterns
     * @return true if resourcePath is excluded by exclusion patterns
     */
    public static boolean isExcludedPath(IPath resourcePath, IPath[] exclusionPatterns) {
        char[] path = resourcePath.toString().toCharArray();
        for (int i = 0, length = exclusionPatterns.length; i < length; i++) {
            char[] pattern = exclusionPatterns[i].toString().toCharArray();
            if (CharOperation.pathMatch(pattern, path, true, '/')) {
                return true;
            }
        }
        return false;
    }

    /*
        
     * @see IClasspathEntry#getExclusionPatterns
     */
    /**
     * Returns whether the given resource path matches one of the exclusion
     * patterns.
     * 
     * @param resourcePath
     * @param exclusionPatterns
     * @return true if resourcePath is excluded
     */
    public static boolean isExcluded(IPath resourcePath, char[][] exclusionPatterns) {
        if (exclusionPatterns == null) {
            return false;
        }
        char[] path = resourcePath.toString().toCharArray();
        for (int i = 0, length = exclusionPatterns.length; i < length; i++) {
            if (CharOperation.pathMatch(exclusionPatterns[i], path, true, '/')) {
                return true;
            }
        }
        return false;
    }

    private static Boolean fgIsJDTCore_1_5 = null;

    /**
     * @return true if JRE 1.5 in enabled.
     */
    public static boolean isJDTCore_1_5() {
        if (fgIsJDTCore_1_5 == null) {
            fgIsJDTCore_1_5 = JavaCore.getDefaultOptions()
                    .containsKey("org.eclipse.jdt.core.compiler.problem.unsafeTypeOperation") ? Boolean.TRUE //$NON-NLS-1$
                            : Boolean.FALSE;
        }
        return fgIsJDTCore_1_5.booleanValue();
    }

    /**
     * Helper method that tests if an classpath entry can be found in a
     * container. <code>null</code> is returned if the entry can not be found
     * or if the container does not allows the configuration of source
     * attachments
     * 
     * @param jproject
     *            The container's parent project
     * @param containerPath
     *            The path of the container
     * @param libPath
     *            The path of the library to be found
     * @return IClasspathEntry A classpath entry from the container of
     *         <code>null</code> if the container can not be modified.
     * @throws JavaModelException 
     */
    public static IClasspathEntry getClasspathEntryToEdit(IJavaProject jproject, IPath containerPath, IPath libPath)
            throws JavaModelException {
        IClasspathContainer container = JavaCore.getClasspathContainer(containerPath, jproject);
        ClasspathContainerInitializer initializer = JavaCore
                .getClasspathContainerInitializer(containerPath.segment(0));
        if (container != null && initializer != null
                && initializer.canUpdateClasspathContainer(containerPath, jproject)) {
            IClasspathEntry[] entries = container.getClasspathEntries();
            for (int i = 0; i < entries.length; i++) {
                IClasspathEntry curr = entries[i];
                IClasspathEntry resolved = JavaCore.getResolvedClasspathEntry(curr);
                if (resolved != null && libPath.equals(resolved.getPath())) {
                    return curr; // return the real entry
                }
            }
        }
        return null; // attachment not possible
    }
}