/******************************************************************************* * Copyright (c) 2001, 2006 IBM Corporation 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: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.jem.internal.adapters.jdom; /* */ import java.io.File; import java.util.*; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.jdt.core.*; import org.eclipse.jem.internal.java.adapters.nls.ResourceHandler; /** * Insert the type's description here. * Creation date: (9/26/2001 11:09:30 AM) * @author: Administrator */ public class JDOMSearchHelper { private static final String RESOLVED_NAME = " :: RESOLVED_NAME :: "; //$NON-NLS-1$ private static final String PERIOD = "."; //$NON-NLS-1$ private static final String BOOLEAN = "boolean"; //$NON-NLS-1$ private static final String BYTE = "byte"; //$NON-NLS-1$ private static final String CHAR = "char"; //$NON-NLS-1$ private static final String SHORT = "short"; //$NON-NLS-1$ private static final String INT = "int"; //$NON-NLS-1$ private static final String LONG = "long"; //$NON-NLS-1$ private static final String FLOAT = "float"; //$NON-NLS-1$ private static final String DOUBLE = "double"; //$NON-NLS-1$ private static final String VOID = "void"; //$NON-NLS-1$ /** * JDOMSearchHelper constructor comment. */ public JDOMSearchHelper() { super(); } /** * If the @simpleName is an inner class, we need to resolve only the declaring class. */ private static String[][] getTypeNameInfo(IType type, String simpleName, boolean isForReflection) throws JavaModelException { String[][] result = null; String declaringName, typeName; typeName = simpleName; if (type != null) { if (isForReflection) typeName = typeName.replace('.', '$'); int index = typeName.indexOf("$"); //$NON-NLS-1$ if (index > 0) { declaringName = typeName.substring(0, index); result = type.resolveType(declaringName); if (result != null) { if (isForReflection) result[0][1] = result[0][1].replace('.', '$'); result[0][1] += typeName.substring(index, typeName.length()); } } else { index = typeName.indexOf("["); //$NON-NLS-1$ if (index > 0) { declaringName = typeName.substring(0, index); result = type.resolveType(declaringName); if (result != null) result[0][1] = result[0][1] + typeName.substring(index); } else result = type.resolveType(typeName); } } return result; } /** * Returns true if the type is a primitive. */ public final static boolean isPrimitive(String type) { return (BOOLEAN.equals(type) || INT.equals(type) || CHAR.equals(type) || SHORT.equals(type) || LONG.equals(type) || FLOAT.equals(type) || DOUBLE.equals(type) || BYTE.equals(type)); } /** * Returns true if the type is a primitive. */ public final static boolean isPrimitiveOrVoid(String type) { return isPrimitive(type) || isVoid(type); } /** * Returns true if the type is a primitive. */ public final static boolean isVoid(String type) { return VOID.equals(type); } /** * Returns true if the two signatures match within the scope of the specified type. */ public static boolean matchTypeSignatures(IType type, String signature1, String signature2) throws JavaModelException { return matchTypeSignatures(type, signature1, signature2, null); } /** * Returns true if the two signatures match within the scope of the specified type. */ public static boolean matchTypeSignatures(IType type, String signature1, String signature2, Map resolvedNameCache) throws JavaModelException { boolean result = false; String sig1 = signature1; String sig2 = signature2; // First check array count. if (Signature.getArrayCount(sig1) == Signature.getArrayCount(sig2)) { // We have the same array count, get the element types for consideration. sig1 = Signature.getElementType(sig1); sig2 = Signature.getElementType(sig2); // There are three cases: // 1) Both are unqualified (both being primitive will fall into this), // 2) Both are qualified, and // 3) One is qualified and the other is not (one could be primitive). // For the first two cases a compare of the readable names will always do. if (!((sig1.indexOf('.') == -1) ^ (sig2.indexOf('.') == -1))) { result = Signature.toString(sig1).equals(Signature.toString(sig2)); } else { // This is case 3. // First root out one being primitive. if (((sig1.charAt(0) == 'Q') || (sig1.charAt(0) == 'L')) && ((sig2.charAt(0) == 'Q') || (sig2.charAt(0) == 'L'))) { // Get the readable name of the qualified signature // and the simple name of the other. String qualifiedName = null; String simpleName = null; if (sig1.indexOf('.') == -1) { qualifiedName = Signature.toString(sig2); simpleName = Signature.toString(sig1); } else { qualifiedName = Signature.toString(sig1); simpleName = Signature.toString(sig2); } // If the simple name resolves to the qualified name, we have a match. result = qualifiedName.equals(resolveSimpleTypeName(type, simpleName, resolvedNameCache)); } } } return result; } private static boolean needsToResolveName(IType type, String simpleName, boolean isForReflection) { boolean retVal = false; if (type != null) { retVal = !(type.isBinary() || (!isForReflection && simpleName.indexOf(PERIOD) > -1) || isPrimitiveOrVoid(simpleName)); } return retVal; } /** * Returns the qualified name for the simple name within the scope of the type. * Returns null if the name can not be resolved. */ public static String resolveSimpleTypeName(IType type, String simpleName) throws JavaModelException { return resolveSimpleTypeName(type, simpleName, null); } /** * Returns the qualified name for the simple name within the scope of the type. * Returns null if the name can not be resolved. */ public static String resolveSimpleTypeName(IType type, String simpleName, Map resolvedNameCache) throws JavaModelException { return resolveSimpleTypeName(type, simpleName, resolvedNameCache, false); } /** * Returns the qualified name for the simple name within the scope of the type. * Returns null if the name can not be resolved. */ public static String resolveSimpleTypeName(IType type, String simpleName, Map resolvedNameCache, boolean isForReflection) throws JavaModelException { if (!needsToResolveName(type, simpleName, isForReflection)) return simpleName; String key = null, qualifiedName = null; if (resolvedNameCache != null) { key = type.getFullyQualifiedName() + RESOLVED_NAME + simpleName; qualifiedName = (String) resolvedNameCache.get(key); } if (qualifiedName == null) { String[][] result = getTypeNameInfo(type, simpleName, isForReflection); if (result != null) { String packName = result[0][0]; if (packName.length() == 0) { qualifiedName = result[0][1]; if (isForReflection) qualifiedName = qualifiedName.replace('.', '$'); } else { StringBuffer b = new StringBuffer(); b.append(result[0][0]).append(PERIOD); String typeName = result[0][1]; if (isForReflection) typeName = typeName.replace('.', '$'); b.append(typeName); qualifiedName = b.toString(); } } else { qualifiedName = simpleName; } if (resolvedNameCache != null) resolvedNameCache.put(key, qualifiedName); } return qualifiedName; } /** * Searches for a matching method and sets it in the * descriptor if found. */ public static IMethod searchForMatchingMethod(IType type, String methodName, String[] parmSigs) throws JavaModelException { return searchForMatchingMethod(type, methodName, parmSigs, null); } /** * Searches for a matching method and sets it in the * descriptor if found. */ public static IMethod searchForMatchingMethod(IType type, String methodName, String[] parmSigs, Map resolvedNameCache) throws JavaModelException { // First get all the methods by this name and with this many parms. IMethod[] allMethods = type.getMethods(); List candidateMethods = new ArrayList(); for (int i = 0; i < allMethods.length; i++) { int parmSigsLength = (parmSigs != null ? parmSigs.length : 0); if ((allMethods[i].getElementName().equals(methodName)) && (allMethods[i].getNumberOfParameters() == parmSigsLength)) candidateMethods.add(allMethods[i]); } // For each candidate consider each parm for a match. // Take the first one that matches on all parms. IMethod next = null; String[] nextParmSigs = null; boolean found = false; Iterator candidateIter = candidateMethods.iterator(); while (!found && (candidateIter.hasNext())) { next = (IMethod) candidateIter.next(); nextParmSigs = next.getParameterTypes(); found = true; for (int i = 0;(found && (i < nextParmSigs.length)); i++) found &= matchTypeSignatures(type, parmSigs[i], nextParmSigs[i], resolvedNameCache); } return found ? next : null; } /** * The returned Object[] will contain two entries. The * first will be the IJavaElement that was found and the * second will be the qualifiedName used to find it. */ protected static Object[] findActualJavaElement(String qualifiedName, IJavaProject javaProject, JDOMAdaptor adaptor) { Object[] result = new Object[2]; if (adaptor == null) result[1] = qualifiedName; else //Ensure the name is qualified result[1] = getResolvedTypeName(qualifiedName, adaptor.getType(), adaptor.getTypeResolutionCache()); result[0] = findJavaElement((String) result[1], javaProject, adaptor); if (result[0] == null) findInnerJavaElement(result, javaProject, adaptor); return result; } /** * The returned Object[] will contain two entries. The * first will be the IJavaElement that was found and the * second will be the qualifiedName used to find it. */ protected static void findInnerJavaElement(Object[] info, IJavaProject javaProject, JDOMAdaptor adaptor) { String qualifiedName, innerName; qualifiedName = (String) info[1]; int index = qualifiedName.lastIndexOf("."); //$NON-NLS-1$ if (index > 0) { innerName = qualifiedName.substring(0, index); String pkgName = innerName; innerName += "$"; //$NON-NLS-1$ innerName += qualifiedName.substring(index + 1, qualifiedName.length()); if (adaptor != null) { //Ensure the name is qualified which it may not be if an inner class innerName = getResolvedTypeName(innerName, adaptor.getType(), adaptor.getTypeResolutionCache()); if (qualifiedName.equals(innerName)) { return; } } info[1] = innerName; info[0] = findJavaElement(innerName, javaProject, adaptor); if (javaProject.getProject().isAccessible()&& info[0] == null) { index = innerName.lastIndexOf("."); //$NON-NLS-1$ if (index > 0 && innerName.substring(0, index).equals(pkgName)) { return; } findInnerJavaElement(info, javaProject, adaptor); } } } protected static IJavaElement findJavaElement(String qualifiedName, IJavaProject javaProject, JDOMAdaptor adaptor) { try { if (javaProject != null) { return javaProject.findType(qualifiedName); } } catch (JavaModelException jme) { System.out.println(ResourceHandler.getString("Error_Looking_Up_Type_ERROR_", (new Object[] { qualifiedName, jme.getMessage()}))); //$NON-NLS-1$ = "Error looking up type: " } return null; } protected static IPath getPathFromQualifiedName(String qualifiedName) { return new Path(qualifiedName.replace('.', File.separatorChar) + ".java"); //$NON-NLS-1$ } /* * Resolve a type name in the context of a Type. * (Borrowed from org.eclipse.jdt.ui.codemanipulation.StubUtility.getResolvedTypeName()) * The input is a simple or qualified name, NOT a signature * The output will be a qualified name, NOT a signature */ public static String getResolvedTypeName(String typeName, IType declaringType, Map typeCache) { String name = typeName; try { name = JDOMSearchHelper.resolveSimpleTypeName(declaringType, typeName, typeCache, true); } catch (JavaModelException e) { // ignore } return name; } public static IType findType(String qualifiedName, boolean useAdvancedForInners, IJavaProject javaProject, JDOMAdaptor adaptor) { IJavaElement found = null; String resolvedName = qualifiedName; if (useAdvancedForInners) { Object[] result = findActualJavaElement(qualifiedName, javaProject, adaptor); found = (IJavaElement) result[0]; resolvedName = (String) result[1]; } else found = findJavaElement(qualifiedName, javaProject, adaptor); if (found != null) if (found instanceof IClassFile) return ((IClassFile) found).getType(); else if (found instanceof ICompilationUnit) { ICompilationUnit foundCU = (ICompilationUnit) found; // strip the ".java", lifted from CompilationUnit.getMainTypeName() String cuMainTypeName = foundCU.getElementName(); cuMainTypeName = cuMainTypeName.substring(0, cuMainTypeName.length() - 5); return foundCU.getType(cuMainTypeName); } else if (found instanceof IType) { IType type = ((IType) found); if (!type.getFullyQualifiedName('$').equals(resolvedName)) { // I don't know why this is here. Sometime in the past for an inner class, the // IType returned was for the outer class, so you would need to search again // for the inner class against the outer class. I don't know how this now can // happen. The code followed above is extremelly complicated, especially when // it is an inner class that isn't fully-qualified that is inside a source file. // It goes through some gyrations for that. I don't know what it would // return in that case. But just in case, the test is here to be safe. int index = resolvedName.lastIndexOf('$'); //$NON-NLS-1$ if (index > -1) return type.getType(resolvedName.substring(index + 1, resolvedName.length())); else return type; } else return type; } return null; } public static IType findType(String packageName, String qualifiedTypeName, IJavaProject javaProject) { try { if (javaProject != null) { return javaProject.findType(packageName, qualifiedTypeName.replace('$', '.')); } } catch (JavaModelException jme) { System.out.println(ResourceHandler.getString("Error_Looking_Up_Type_ERROR_", (new Object[] { packageName + "." + qualifiedTypeName, jme.getMessage()}))); //$NON-NLS-1$ //$NON-NLS-2$ = "Error looking up type: " } return null; } }