package lapsePlus; /* * Binding2JavaModel.java, version 2.8, 2010 */ import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.jdt.core.IClassFile; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IField; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; 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.JavaModelException; import org.eclipse.jdt.core.Signature; import org.eclipse.jdt.core.dom.IMethodBinding; import org.eclipse.jdt.core.dom.IPackageBinding; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.IVariableBinding; /** * A helper class to convert compiler bindings into corresponding * Java elements. */ public class Binding2JavaModel { private Binding2JavaModel(){} public static ICompilationUnit findCompilationUnit(ITypeBinding typeBinding, IJavaProject project) throws JavaModelException { if (!typeBinding.isFromSource()) { return null; } while (typeBinding != null && !typeBinding.isTopLevel()) { typeBinding= typeBinding.getDeclaringClass(); } if (typeBinding != null) { IPackageBinding pack= typeBinding.getPackage(); String packageName= pack.isUnnamed() ? "" : pack.getName(); //$NON-NLS-1$ IType type= project.findType(packageName, typeBinding.getName()); if (type != null) { return type.getCompilationUnit(); } } return null; } /** * Converts the given <code>IVariableBinding</code> into a <code>IField</code> * using the classpath defined by the given Java project. Returns <code>null</code> * if the conversion isn't possible. */ public static IField find(IVariableBinding field, IJavaProject in) throws JavaModelException { IType declaringClass = find(field.getDeclaringClass(), in); if (declaringClass == null) return null; IField foundField= declaringClass.getField(field.getName()); if (! foundField.exists()) return null; return foundField; } /** * Converts the given <code>ITypeBinding</code> into a <code>IType</code> * using the classpath defined by the given Java project. Returns <code>null</code> * if the conversion isn't possible. */ public static IType find(ITypeBinding type, IJavaProject scope) throws JavaModelException { if (type.isPrimitive()) return null; String[] typeElements= getNameComponents(type); IJavaElement element= scope.findElement(getPathToCompilationUnit(type.getPackage(), typeElements[0])); IType candidate= null; if (element instanceof ICompilationUnit) { candidate= ((ICompilationUnit)element).getType(typeElements[0]); } else if (element instanceof IClassFile) { candidate= ((IClassFile)element).getType(); } else if (element == null){ if (type.isMember()) candidate= findType(scope, getFullyQualifiedImportName(type.getDeclaringClass())); else candidate= findType(scope, getFullyQualifiedImportName(type)); } if (candidate == null || typeElements.length == 1) return candidate; return findTypeInType(typeElements, candidate); } /** * Finds a type by its qualified type name (dot separated). * @param jproject The java project to search in * @param str 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 */ 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; } 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; } /** * 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 */ public static String getFullyQualifiedName(IType type) { return type.getFullyQualifiedName('.'); } /** * Finds the given <code>IMethodBinding</code> in the given <code>IType</code>. Returns * <code>null</code> if the type doesn't contain a corresponding method. */ public static IMethod find(IMethodBinding method, IType type) throws JavaModelException { IMethod[] candidates= type.getMethods(); for (int i= 0; i < candidates.length; i++) { IMethod candidate= candidates[i]; if (candidate.getElementName().equals(method.getName()) && sameParameters(method, candidate)) { return candidate; } } return null; } public static IMethod findIncludingSupertypes(IMethodBinding method, IType type, IProgressMonitor pm) throws JavaModelException { IMethod inThisType= find(method, type); if (inThisType != null) return inThisType; IType[] superTypes= getAllSuperTypes(type, pm); for (int i= 0; i < superTypes.length; i++) { IMethod m= find(method, superTypes[i]); if (m != null) return m; } return null; } public static IMethod find(IMethodBinding method, IJavaProject scope) throws JavaModelException { IType type= find(method.getDeclaringClass(), scope); if (type == null) return null; return find(method, type); } //---- Helper methods to convert a type -------------------------------------------- private static IPath getPathToCompilationUnit(IPackageBinding packageBinding, String topLevelTypeName) { IPath result= new Path(""); //$NON-NLS-1$ String[] packageNames= packageBinding.getNameComponents(); for (int i= 0; i < packageNames.length; i++) { result= result.append(packageNames[i]); } return result.append(topLevelTypeName + ".java"); //$NON-NLS-1$ } private static IType findTypeInType(String[] typeElements, IType jmType) { IType result= jmType; for (int i= 1; i < typeElements.length; i++) { result= result.getType(typeElements[i]); if (!result.exists()) return null; } return result == jmType ? null : result; } //---- Helper methods to convert a method --------------------------------------------- private static boolean sameParameters(IMethodBinding method, IMethod candidate) throws JavaModelException { ITypeBinding[] methodParamters= method.getParameterTypes(); String[] candidateParameters= candidate.getParameterTypes(); if (methodParamters.length != candidateParameters.length) return false; IType scope= candidate.getDeclaringType(); for (int i= 0; i < methodParamters.length; i++) { ITypeBinding methodParameter= methodParamters[i]; String candidateParameter= candidateParameters[i]; if (!sameParameter(methodParameter, candidateParameter, scope)) return false; } return true; } private static boolean sameParameter(ITypeBinding type, String candidate, IType scope) throws JavaModelException { if (type.getDimensions() != Signature.getArrayCount(candidate)) return false; // Normalizes types if (type.isArray()) type= type.getElementType(); candidate= Signature.getElementType(candidate); if (isPrimitiveType(candidate) || type.isPrimitive()) { return type.getName().equals(Signature.toString(candidate)); } else { if (isResolvedType(candidate)) { return Signature.toString(candidate).equals(getFullyQualifiedName(type)); } else { String[][] qualifiedCandidates= scope.resolveType(Signature.toString(candidate)); if (qualifiedCandidates == null || qualifiedCandidates.length == 0) return false; String packageName= type.getPackage().isUnnamed() ? "" : type.getPackage().getName(); //$NON-NLS-1$ String typeName= getTypeQualifiedName(type); for (int i= 0; i < qualifiedCandidates.length; i++) { String[] qualifiedCandidate= qualifiedCandidates[i]; if (qualifiedCandidate[0].equals(packageName) && qualifiedCandidate[1].equals(typeName)) { return true; } } } } return false; } public static String getTypeQualifiedName(ITypeBinding type) { StringBuffer buffer= new StringBuffer(); createName(type, false, buffer); return buffer.toString(); } private static boolean isPrimitiveType(String s) { char c= s.charAt(0); return c != Signature.C_RESOLVED && c != Signature.C_UNRESOLVED; } private static boolean isResolvedType(String s) { int arrayCount= Signature.getArrayCount(s); return s.charAt(arrayCount) == Signature.C_RESOLVED; } public static String[] getNameComponents(ITypeBinding type) { List<String> result= new ArrayList<String>(5); createName(type, false, result); return (String[]) result.toArray(new String[result.size()]); } private static void createName(ITypeBinding type, boolean includePackage, StringBuffer buffer) { ITypeBinding baseType= type; if (type.isArray()) { baseType= type.getElementType(); } if (!baseType.isPrimitive() && !baseType.isNullType()) { ITypeBinding declaringType= baseType.getDeclaringClass(); if (declaringType != null) { createName(declaringType, includePackage, buffer); buffer.append('.'); } else if (includePackage && !baseType.getPackage().isUnnamed()) { buffer.append(baseType.getPackage().getName()); buffer.append('.'); } } if (!baseType.isAnonymous()) { buffer.append(type.getName()); } else { buffer.append("$local$"); //$NON-NLS-1$ } } private static void createName(ITypeBinding type, boolean includePackage, List<String> list) { ITypeBinding baseType= type; if (type.isArray()) { baseType= type.getElementType(); } if (!baseType.isPrimitive() && !baseType.isNullType()) { ITypeBinding declaringType= baseType.getDeclaringClass(); if (declaringType != null) { createName(declaringType, includePackage, list); } else if (includePackage && !baseType.getPackage().isUnnamed()) { String[] components= baseType.getPackage().getNameComponents(); for (int i= 0; i < components.length; i++) { list.add(components[i]); } } } if (!baseType.isAnonymous()) { list.add(type.getName()); } else { list.add("$local$"); //$NON-NLS-1$ } } public static String getFullyQualifiedImportName(ITypeBinding type) { if (type.isArray()) { return getFullyQualifiedName(type.getElementType()); } else if (type.isAnonymous()) { return getFullyQualifiedImportName(type.getSuperclass()); } else { return getFullyQualifiedName(type); } } public static String getFullyQualifiedName(ITypeBinding type) { StringBuffer buffer= new StringBuffer(); createName(type, true, buffer); return buffer.toString(); } public static IType[] getAllSuperTypes(IType type, IProgressMonitor pm) throws JavaModelException { //workaround for bugs 23644 and 23656 try{ pm.beginTask("", 3); //$NON-NLS-1$ ITypeHierarchy hierarchy= type.newSupertypeHierarchy(new SubProgressMonitor(pm, 1)); IProgressMonitor subPm= new SubProgressMonitor(pm, 2); List<IType> typeList= Arrays.asList(hierarchy.getAllSupertypes(type)); subPm.beginTask("", typeList.size()); //$NON-NLS-1$ Set<IType> types= new HashSet<IType>(typeList); for (Iterator iter= typeList.iterator(); iter.hasNext();) { IType superType= (IType)iter.next(); IType[] superTypes= getAllSuperTypes(superType, new SubProgressMonitor(subPm, 1)); types.addAll(Arrays.asList(superTypes)); } types.add(type.getJavaProject().findType("java.lang.Object"));//$NON-NLS-1$ subPm.done(); return (IType[]) types.toArray(new IType[types.size()]); } finally { pm.done(); } } }