| /******************************************************************************* |
| * Copyright (c) 2000, 2013 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.aspectj.org.eclipse.jdt.internal.core.util; |
| |
| import java.io.*; |
| import java.net.URI; |
| import java.util.*; |
| import java.util.zip.ZipEntry; |
| import java.util.zip.ZipFile; |
| |
| import org.eclipse.core.filesystem.EFS; |
| import org.eclipse.core.filesystem.IFileStore; |
| import org.eclipse.core.resources.*; |
| import org.eclipse.core.runtime.*; |
| import org.eclipse.core.runtime.content.IContentType; |
| import org.eclipse.core.runtime.preferences.IScopeContext; |
| import org.eclipse.core.runtime.preferences.InstanceScope; |
| import org.aspectj.org.eclipse.jdt.core.*; |
| import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation; |
| import org.aspectj.org.eclipse.jdt.core.dom.ASTNode; |
| import org.aspectj.org.eclipse.jdt.core.dom.ArrayType; |
| import org.aspectj.org.eclipse.jdt.core.dom.ParameterizedType; |
| import org.aspectj.org.eclipse.jdt.core.dom.PrimitiveType; |
| import org.aspectj.org.eclipse.jdt.core.dom.QualifiedType; |
| import org.aspectj.org.eclipse.jdt.core.dom.SimpleType; |
| import org.aspectj.org.eclipse.jdt.core.dom.Type; |
| import org.aspectj.org.eclipse.jdt.core.dom.WildcardType; |
| import org.aspectj.org.eclipse.jdt.core.util.IClassFileAttribute; |
| import org.aspectj.org.eclipse.jdt.core.util.IClassFileReader; |
| import org.aspectj.org.eclipse.jdt.core.util.ICodeAttribute; |
| import org.aspectj.org.eclipse.jdt.core.util.IFieldInfo; |
| import org.aspectj.org.eclipse.jdt.core.util.IMethodInfo; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.AnnotationMethodDeclaration; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Argument; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.UnionTypeReference; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeReference; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.env.ClassSignature; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.env.EnumConstantSignature; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.env.IBinaryAnnotation; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.env.IDependent; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.impl.Constant; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.Binding; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.FieldBinding; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodBinding; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeIds; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.parser.ScannerHelper; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.util.SuffixConstants; |
| import org.aspectj.org.eclipse.jdt.internal.core.Annotation; |
| import org.aspectj.org.eclipse.jdt.internal.core.ClassFile; |
| import org.aspectj.org.eclipse.jdt.internal.core.JavaElement; |
| import org.aspectj.org.eclipse.jdt.internal.core.JavaModelManager; |
| import org.aspectj.org.eclipse.jdt.internal.core.Member; |
| import org.aspectj.org.eclipse.jdt.internal.core.MemberValuePair; |
| import org.aspectj.org.eclipse.jdt.internal.core.PackageFragment; |
| import org.aspectj.org.eclipse.jdt.internal.core.PackageFragmentRoot; |
| import org.eclipse.jface.text.BadLocationException; |
| import org.eclipse.text.edits.MalformedTreeException; |
| import org.eclipse.text.edits.TextEdit; |
| |
| /** |
| * Provides convenient utility methods to other types in this package. |
| */ |
| @SuppressWarnings({ "rawtypes", "unchecked" }) |
| public class Util { |
| |
| public interface Comparable { |
| /** |
| * Returns 0 if this and c are equal, >0 if this is greater than c, |
| * or <0 if this is less than c. |
| */ |
| int compareTo(Comparable c); |
| } |
| |
| public interface Comparer { |
| /** |
| * Returns 0 if a and b are equal, >0 if a is greater than b, |
| * or <0 if a is less than b. |
| */ |
| int compare(Object a, Object b); |
| } |
| |
| public static interface BindingsToNodesMap { |
| public org.aspectj.org.eclipse.jdt.internal.compiler.ast.ASTNode get(Binding binding); |
| } |
| |
| private static final char ARGUMENTS_DELIMITER = '#'; |
| |
| private static final String EMPTY_ARGUMENT = " "; //$NON-NLS-1$ |
| |
| private static char[][] JAVA_LIKE_EXTENSIONS; |
| |
| private static final char[] BOOLEAN = "boolean".toCharArray(); //$NON-NLS-1$ |
| private static final char[] BYTE = "byte".toCharArray(); //$NON-NLS-1$ |
| private static final char[] CHAR = "char".toCharArray(); //$NON-NLS-1$ |
| private static final char[] DOUBLE = "double".toCharArray(); //$NON-NLS-1$ |
| private static final char[] FLOAT = "float".toCharArray(); //$NON-NLS-1$ |
| private static final char[] INT = "int".toCharArray(); //$NON-NLS-1$ |
| private static final char[] LONG = "long".toCharArray(); //$NON-NLS-1$ |
| private static final char[] SHORT = "short".toCharArray(); //$NON-NLS-1$ |
| private static final char[] VOID = "void".toCharArray(); //$NON-NLS-1$ |
| private static final char[] INIT = "<init>".toCharArray(); //$NON-NLS-1$ |
| |
| private static final String TASK_PRIORITIES_PROBLEM = "TASK_PRIORITIES_PB"; //$NON-NLS-1$ |
| private static List fgRepeatedMessages= new ArrayList(5); |
| |
| private Util() { |
| // cannot be instantiated |
| } |
| |
| /** |
| * Returns a new array adding the second array at the end of first array. |
| * It answers null if the first and second are null. |
| * If the first array is null or if it is empty, then a new array is created with second. |
| * If the second array is null, then the first array is returned. |
| * <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li><pre> |
| * first = null |
| * second = "a" |
| * => result = {"a"} |
| * </pre> |
| * <li><pre> |
| * first = {"a"} |
| * second = null |
| * => result = {"a"} |
| * </pre> |
| * </li> |
| * <li><pre> |
| * first = {"a"} |
| * second = {"b"} |
| * => result = {"a", "b"} |
| * </pre> |
| * </li> |
| * </ol> |
| * |
| * @param first the first array to concatenate |
| * @param second the array to add at the end of the first array |
| * @return a new array adding the second array at the end of first array, or null if the two arrays are null. |
| */ |
| public static final String[] arrayConcat(String[] first, String second) { |
| if (second == null) |
| return first; |
| if (first == null) |
| return new String[] {second}; |
| |
| int length = first.length; |
| if (first.length == 0) { |
| return new String[] {second}; |
| } |
| |
| String[] result = new String[length + 1]; |
| System.arraycopy(first, 0, result, 0, length); |
| result[length] = second; |
| return result; |
| } |
| |
| /** |
| * Checks the type signature in String sig, |
| * starting at start and ending before end (end is not included). |
| * Returns the index of the character immediately after the signature if valid, |
| * or -1 if not valid. |
| */ |
| private static int checkTypeSignature(String sig, int start, int end, boolean allowVoid) { |
| if (start >= end) return -1; |
| int i = start; |
| char c = sig.charAt(i++); |
| int nestingDepth = 0; |
| while (c == '[') { |
| ++nestingDepth; |
| if (i >= end) return -1; |
| c = sig.charAt(i++); |
| } |
| switch (c) { |
| case 'B': |
| case 'C': |
| case 'D': |
| case 'F': |
| case 'I': |
| case 'J': |
| case 'S': |
| case 'Z': |
| break; |
| case 'V': |
| if (!allowVoid) return -1; |
| // array of void is not allowed |
| if (nestingDepth != 0) return -1; |
| break; |
| case 'L': |
| int semicolon = sig.indexOf(';', i); |
| // Must have at least one character between L and ; |
| if (semicolon <= i || semicolon >= end) return -1; |
| i = semicolon + 1; |
| break; |
| default: |
| return -1; |
| } |
| return i; |
| } |
| |
| /** |
| * Combines two hash codes to make a new one. |
| */ |
| public static int combineHashCodes(int hashCode1, int hashCode2) { |
| return hashCode1 * 17 + hashCode2; |
| } |
| |
| /** |
| * Compares two byte arrays. |
| * Returns <0 if a byte in a is less than the corresponding byte in b, or if a is shorter, or if a is null. |
| * Returns >0 if a byte in a is greater than the corresponding byte in b, or if a is longer, or if b is null. |
| * Returns 0 if they are equal or both null. |
| */ |
| public static int compare(byte[] a, byte[] b) { |
| if (a == b) |
| return 0; |
| if (a == null) |
| return -1; |
| if (b == null) |
| return 1; |
| int len = Math.min(a.length, b.length); |
| for (int i = 0; i < len; ++i) { |
| int diff = a[i] - b[i]; |
| if (diff != 0) |
| return diff; |
| } |
| if (a.length > len) |
| return 1; |
| if (b.length > len) |
| return -1; |
| return 0; |
| } |
| /** |
| * Compares two strings lexicographically. |
| * The comparison is based on the Unicode value of each character in |
| * the strings. |
| * |
| * @return the value <code>0</code> if the str1 is equal to str2; |
| * a value less than <code>0</code> if str1 |
| * is lexicographically less than str2; |
| * and a value greater than <code>0</code> if str1 is |
| * lexicographically greater than str2. |
| */ |
| public static int compare(char[] str1, char[] str2) { |
| int len1= str1.length; |
| int len2= str2.length; |
| int n= Math.min(len1, len2); |
| int i= 0; |
| while (n-- != 0) { |
| char c1= str1[i]; |
| char c2= str2[i++]; |
| if (c1 != c2) { |
| return c1 - c2; |
| } |
| } |
| return len1 - len2; |
| } |
| /** |
| * Concatenate a String[] compound name to a continuous char[]. |
| */ |
| public static char[] concatCompoundNameToCharArray(String[] compoundName) { |
| if (compoundName == null) return null; |
| int length = compoundName.length; |
| if (length == 0) return new char[0]; |
| int size = 0; |
| for (int i=0; i<length; i++) { |
| size += compoundName[i].length(); |
| } |
| char[] compoundChars = new char[size+length-1]; |
| int pos = 0; |
| for (int i=0; i<length; i++) { |
| String name = compoundName[i]; |
| if (i > 0) compoundChars[pos++] = '.'; |
| int nameLength = name.length(); |
| name.getChars(0, nameLength, compoundChars, pos); |
| pos += nameLength; |
| } |
| return compoundChars; |
| } |
| public static String concatenateName(String name1, String name2, char separator) { |
| 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(separator); |
| } |
| buf.append(name2); |
| } |
| return buf.toString(); |
| } |
| /** |
| * Returns the concatenation of the given array parts using the given separator between each part. |
| * <br> |
| * <br> |
| * For example:<br> |
| * <ol> |
| * <li><pre> |
| * array = {"a", "b"} |
| * separator = '.' |
| * => result = "a.b" |
| * </pre> |
| * </li> |
| * <li><pre> |
| * array = {} |
| * separator = '.' |
| * => result = "" |
| * </pre></li> |
| * </ol> |
| * |
| * @param array the given array |
| * @param separator the given separator |
| * @return the concatenation of the given array parts using the given separator between each part |
| */ |
| public static final String concatWith(String[] array, char separator) { |
| StringBuffer buffer = new StringBuffer(); |
| for (int i = 0, length = array.length; i < length; i++) { |
| buffer.append(array[i]); |
| if (i < length - 1) |
| buffer.append(separator); |
| } |
| return buffer.toString(); |
| } |
| |
| /** |
| * Returns the concatenation of the given array parts using the given separator between each |
| * part and appending the given name at the end. |
| * <br> |
| * <br> |
| * For example:<br> |
| * <ol> |
| * <li><pre> |
| * name = "c" |
| * array = { "a", "b" } |
| * separator = '.' |
| * => result = "a.b.c" |
| * </pre> |
| * </li> |
| * <li><pre> |
| * name = null |
| * array = { "a", "b" } |
| * separator = '.' |
| * => result = "a.b" |
| * </pre></li> |
| * <li><pre> |
| * name = " c" |
| * array = null |
| * separator = '.' |
| * => result = "c" |
| * </pre></li> |
| * </ol> |
| * |
| * @param array the given array |
| * @param name the given name |
| * @param separator the given separator |
| * @return the concatenation of the given array parts using the given separator between each |
| * part and appending the given name at the end |
| */ |
| public static final String concatWith( |
| String[] array, |
| String name, |
| char separator) { |
| |
| if (array == null || array.length == 0) return name; |
| if (name == null || name.length() == 0) return concatWith(array, separator); |
| StringBuffer buffer = new StringBuffer(); |
| for (int i = 0, length = array.length; i < length; i++) { |
| buffer.append(array[i]); |
| buffer.append(separator); |
| } |
| buffer.append(name); |
| return buffer.toString(); |
| |
| } |
| /** |
| * Converts a type signature from the IBinaryType representation to the DC representation. |
| */ |
| public static String convertTypeSignature(char[] sig, int start, int length) { |
| return new String(sig, start, length).replace('/', '.'); |
| } |
| |
| /* |
| * Returns the default java extension (".java"). |
| * To be used when the extension is not known. |
| */ |
| public static String defaultJavaExtension() { |
| return SuffixConstants.SUFFIX_STRING_java; |
| } |
| |
| /** |
| * Apply the given edit on the given string and return the updated string. |
| * Return the given string if anything wrong happen while applying the edit. |
| * |
| * @param original the given string |
| * @param edit the given edit |
| * |
| * @return the updated string |
| */ |
| public final static String editedString(String original, TextEdit edit) { |
| if (edit == null) { |
| return original; |
| } |
| SimpleDocument document = new SimpleDocument(original); |
| try { |
| edit.apply(document, TextEdit.NONE); |
| return document.get(); |
| } catch (MalformedTreeException e) { |
| e.printStackTrace(); |
| } catch (BadLocationException e) { |
| e.printStackTrace(); |
| } |
| return original; |
| } |
| |
| /** |
| * Returns true iff str.toLowerCase().endsWith(end.toLowerCase()) |
| * implementation is not creating extra strings. |
| */ |
| public final static boolean endsWithIgnoreCase(String str, String end) { |
| |
| int strLength = str == null ? 0 : str.length(); |
| int endLength = end == null ? 0 : end.length(); |
| |
| // return false if the string is smaller than the end. |
| if(endLength > strLength) |
| return false; |
| |
| // return false if any character of the end are |
| // not the same in lower case. |
| for(int i = 1 ; i <= endLength; i++){ |
| if(ScannerHelper.toLowerCase(end.charAt(endLength - i)) != ScannerHelper.toLowerCase(str.charAt(strLength - i))) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /** |
| * Compares two arrays using equals() on the elements. |
| * Neither can be null. Only the first len elements are compared. |
| * Return false if either array is shorter than len. |
| */ |
| public static boolean equalArrays(Object[] a, Object[] b, int len) { |
| if (a == b) return true; |
| if (a.length < len || b.length < len) return false; |
| for (int i = 0; i < len; ++i) { |
| if (a[i] == null) { |
| if (b[i] != null) return false; |
| } else { |
| if (!a[i].equals(b[i])) return false; |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * Compares two arrays using equals() on the elements. |
| * Either or both arrays may be null. |
| * Returns true if both are null. |
| * Returns false if only one is null. |
| * If both are arrays, returns true iff they have the same length and |
| * all elements are equal. |
| */ |
| public static boolean equalArraysOrNull(int[] a, int[] b) { |
| if (a == b) |
| return true; |
| if (a == null || b == null) |
| return false; |
| int len = a.length; |
| if (len != b.length) |
| return false; |
| for (int i = 0; i < len; ++i) { |
| if (a[i] != b[i]) |
| return false; |
| } |
| return true; |
| } |
| |
| /** |
| * Compares two arrays using equals() on the elements. |
| * Either or both arrays may be null. |
| * Returns true if both are null. |
| * Returns false if only one is null. |
| * If both are arrays, returns true iff they have the same length and |
| * all elements compare true with equals. |
| */ |
| public static boolean equalArraysOrNull(Object[] a, Object[] b) { |
| if (a == b) return true; |
| if (a == null || b == null) return false; |
| |
| int len = a.length; |
| if (len != b.length) return false; |
| // walk array from end to beginning as this optimizes package name cases |
| // where the first part is always the same (e.g. org.aspectj.org.eclipse.jdt) |
| for (int i = len-1; i >= 0; i--) { |
| if (a[i] == null) { |
| if (b[i] != null) return false; |
| } else { |
| if (!a[i].equals(b[i])) return false; |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * Compares two arrays using equals() on the elements. |
| * The arrays are first sorted. |
| * Either or both arrays may be null. |
| * Returns true if both are null. |
| * Returns false if only one is null. |
| * If both are arrays, returns true iff they have the same length and |
| * iff, after sorting both arrays, all elements compare true with equals. |
| * The original arrays are left untouched. |
| */ |
| public static boolean equalArraysOrNullSortFirst(Comparable[] a, Comparable[] b) { |
| if (a == b) return true; |
| if (a == null || b == null) return false; |
| int len = a.length; |
| if (len != b.length) return false; |
| if (len >= 2) { // only need to sort if more than two items |
| a = sortCopy(a); |
| b = sortCopy(b); |
| } |
| for (int i = 0; i < len; ++i) { |
| if (!a[i].equals(b[i])) return false; |
| } |
| return true; |
| } |
| |
| /** |
| * Compares two String arrays using equals() on the elements. |
| * The arrays are first sorted. |
| * Either or both arrays may be null. |
| * Returns true if both are null. |
| * Returns false if only one is null. |
| * If both are arrays, returns true iff they have the same length and |
| * iff, after sorting both arrays, all elements compare true with equals. |
| * The original arrays are left untouched. |
| */ |
| public static boolean equalArraysOrNullSortFirst(String[] a, String[] b) { |
| if (a == b) return true; |
| if (a == null || b == null) return false; |
| int len = a.length; |
| if (len != b.length) return false; |
| if (len >= 2) { // only need to sort if more than two items |
| a = sortCopy(a); |
| b = sortCopy(b); |
| } |
| for (int i = 0; i < len; ++i) { |
| if (!a[i].equals(b[i])) return false; |
| } |
| return true; |
| } |
| |
| /** |
| * Compares two objects using equals(). |
| * Either or both array may be null. |
| * Returns true if both are null. |
| * Returns false if only one is null. |
| * Otherwise, return the result of comparing with equals(). |
| */ |
| public static boolean equalOrNull(Object a, Object b) { |
| if (a == b) { |
| return true; |
| } |
| if (a == null || b == null) { |
| return false; |
| } |
| return a.equals(b); |
| } |
| |
| /* |
| * Returns whether the given file name equals to the given string ignoring the java like extension |
| * of the file name. |
| * Returns false if it is not a java like file name. |
| */ |
| public static boolean equalsIgnoreJavaLikeExtension(String fileName, String string) { |
| int fileNameLength = fileName.length(); |
| int stringLength = string.length(); |
| if (fileNameLength < stringLength) return false; |
| for (int i = 0; i < stringLength; i ++) { |
| if (fileName.charAt(i) != string.charAt(i)) { |
| return false; |
| } |
| } |
| char[][] javaLikeExtensions = getJavaLikeExtensions(); |
| suffixes: for (int i = 0, length = javaLikeExtensions.length; i < length; i++) { |
| char[] suffix = javaLikeExtensions[i]; |
| int extensionStart = stringLength+1; |
| if (extensionStart + suffix.length != fileNameLength) continue; |
| if (fileName.charAt(stringLength) != '.') continue; |
| for (int j = extensionStart; j < fileNameLength; j++) { |
| if (fileName.charAt(j) != suffix[j-extensionStart]) |
| continue suffixes; |
| } |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Given a qualified name, extract the last component. |
| * If the input is not qualified, the same string is answered. |
| */ |
| public static String extractLastName(String qualifiedName) { |
| int i = qualifiedName.lastIndexOf('.'); |
| if (i == -1) return qualifiedName; |
| return qualifiedName.substring(i+1); |
| } |
| |
| /** |
| * Extracts the parameter types from a method signature. |
| */ |
| public static String[] extractParameterTypes(char[] sig) { |
| int count = getParameterCount(sig); |
| String[] result = new String[count]; |
| if (count == 0) |
| return result; |
| int i = CharOperation.indexOf('(', sig) + 1; |
| count = 0; |
| int len = sig.length; |
| int start = i; |
| for (;;) { |
| if (i == len) |
| break; |
| char c = sig[i]; |
| if (c == ')') |
| break; |
| if (c == '[') { |
| ++i; |
| } else |
| if (c == 'L') { |
| i = CharOperation.indexOf(';', sig, i + 1) + 1; |
| Assert.isTrue(i != 0); |
| result[count++] = convertTypeSignature(sig, start, i - start); |
| start = i; |
| } else { |
| ++i; |
| result[count++] = convertTypeSignature(sig, start, i - start); |
| start = i; |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * Extracts the return type from a method signature. |
| */ |
| public static String extractReturnType(String sig) { |
| int i = sig.lastIndexOf(')'); |
| Assert.isTrue(i != -1); |
| return sig.substring(i+1); |
| } |
| private static IFile findFirstClassFile(IFolder folder) { |
| try { |
| IResource[] members = folder.members(); |
| for (int i = 0, max = members.length; i < max; i++) { |
| IResource member = members[i]; |
| if (member.getType() == IResource.FOLDER) { |
| return findFirstClassFile((IFolder)member); |
| } else if (org.aspectj.org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(member.getName())) { |
| return (IFile) member; |
| } |
| } |
| } catch (CoreException e) { |
| // ignore |
| } |
| return null; |
| } |
| |
| /** |
| * Finds the first line separator used by the given text. |
| * |
| * @return </code>"\n"</code> or </code>"\r"</code> or </code>"\r\n"</code>, |
| * or <code>null</code> if none found |
| */ |
| public static String findLineSeparator(char[] text) { |
| // find the first line separator |
| int length = text.length; |
| if (length > 0) { |
| char nextChar = text[0]; |
| for (int i = 0; i < length; i++) { |
| char currentChar = nextChar; |
| nextChar = i < length-1 ? text[i+1] : ' '; |
| switch (currentChar) { |
| case '\n': return "\n"; //$NON-NLS-1$ |
| case '\r': return nextChar == '\n' ? "\r\n" : "\r"; //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| } |
| } |
| // not found |
| return null; |
| } |
| |
| public static IClassFileAttribute getAttribute(IClassFileReader classFileReader, char[] attributeName) { |
| IClassFileAttribute[] attributes = classFileReader.getAttributes(); |
| for (int i = 0, max = attributes.length; i < max; i++) { |
| if (CharOperation.equals(attributes[i].getAttributeName(), attributeName)) { |
| return attributes[i]; |
| } |
| } |
| return null; |
| } |
| |
| public static IClassFileAttribute getAttribute(ICodeAttribute codeAttribute, char[] attributeName) { |
| IClassFileAttribute[] attributes = codeAttribute.getAttributes(); |
| for (int i = 0, max = attributes.length; i < max; i++) { |
| if (CharOperation.equals(attributes[i].getAttributeName(), attributeName)) { |
| return attributes[i]; |
| } |
| } |
| return null; |
| } |
| |
| public static IClassFileAttribute getAttribute(IFieldInfo fieldInfo, char[] attributeName) { |
| IClassFileAttribute[] attributes = fieldInfo.getAttributes(); |
| for (int i = 0, max = attributes.length; i < max; i++) { |
| if (CharOperation.equals(attributes[i].getAttributeName(), attributeName)) { |
| return attributes[i]; |
| } |
| } |
| return null; |
| } |
| |
| public static IClassFileAttribute getAttribute(IMethodInfo methodInfo, char[] attributeName) { |
| IClassFileAttribute[] attributes = methodInfo.getAttributes(); |
| for (int i = 0, max = attributes.length; i < max; i++) { |
| if (CharOperation.equals(attributes[i].getAttributeName(), attributeName)) { |
| return attributes[i]; |
| } |
| } |
| return null; |
| } |
| |
| private static IClassFile getClassFile(char[] fileName) { |
| int jarSeparator = CharOperation.indexOf(IDependent.JAR_FILE_ENTRY_SEPARATOR, fileName); |
| int pkgEnd = CharOperation.lastIndexOf('/', fileName); // pkgEnd is exclusive |
| if (pkgEnd == -1) |
| pkgEnd = CharOperation.lastIndexOf(File.separatorChar, fileName); |
| if (jarSeparator != -1 && pkgEnd < jarSeparator) // if in a jar and no slash, it is a default package -> pkgEnd should be equal to jarSeparator |
| pkgEnd = jarSeparator; |
| if (pkgEnd == -1) |
| return null; |
| IPackageFragment pkg = getPackageFragment(fileName, pkgEnd, jarSeparator); |
| if (pkg == null) return null; |
| int start; |
| return pkg.getClassFile(new String(fileName, start = pkgEnd + 1, fileName.length - start)); |
| } |
| |
| private static ICompilationUnit getCompilationUnit(char[] fileName, WorkingCopyOwner workingCopyOwner) { |
| char[] slashSeparatedFileName = CharOperation.replaceOnCopy(fileName, File.separatorChar, '/'); |
| int pkgEnd = CharOperation.lastIndexOf('/', slashSeparatedFileName); // pkgEnd is exclusive |
| if (pkgEnd == -1) |
| return null; |
| IPackageFragment pkg = getPackageFragment(slashSeparatedFileName, pkgEnd, -1/*no jar separator for .java files*/); |
| if (pkg == null) return null; |
| int start; |
| ICompilationUnit cu = pkg.getCompilationUnit(new String(slashSeparatedFileName, start = pkgEnd+1, slashSeparatedFileName.length - start)); |
| if (workingCopyOwner != null) { |
| ICompilationUnit workingCopy = cu.findWorkingCopy(workingCopyOwner); |
| if (workingCopy != null) |
| return workingCopy; |
| } |
| return cu; |
| } |
| |
| /** |
| * Returns the registered Java like extensions. |
| */ |
| public static char[][] getJavaLikeExtensions() { |
| if (JAVA_LIKE_EXTENSIONS == null) { |
| IContentType javaContentType = Platform.getContentTypeManager().getContentType(JavaCore.JAVA_SOURCE_CONTENT_TYPE); |
| HashSet fileExtensions = new HashSet(); |
| // content types derived from java content type should be included (https://bugs.eclipse.org/bugs/show_bug.cgi?id=121715) |
| IContentType[] contentTypes = Platform.getContentTypeManager().getAllContentTypes(); |
| for (int i = 0, length = contentTypes.length; i < length; i++) { |
| if (contentTypes[i].isKindOf(javaContentType)) { // note that javaContentType.isKindOf(javaContentType) == true |
| String[] fileExtension = contentTypes[i].getFileSpecs(IContentType.FILE_EXTENSION_SPEC); |
| for (int j = 0, length2 = fileExtension.length; j < length2; j++) { |
| fileExtensions.add(fileExtension[j]); |
| } |
| } |
| } |
| int length = fileExtensions.size(); |
| // note that file extensions contains "java" as it is defined in JDT Core's plugin.xml |
| char[][] extensions = new char[length][]; |
| extensions[0] = SuffixConstants.EXTENSION_java.toCharArray(); // ensure that "java" is first |
| int index = 1; |
| Iterator iterator = fileExtensions.iterator(); |
| while (iterator.hasNext()) { |
| String fileExtension = (String) iterator.next(); |
| if (SuffixConstants.EXTENSION_java.equals(fileExtension)) |
| continue; |
| extensions[index++] = fileExtension.toCharArray(); |
| } |
| JAVA_LIKE_EXTENSIONS = extensions; |
| } |
| return JAVA_LIKE_EXTENSIONS; |
| } |
| /** |
| * Get the jdk level of this root. |
| * The value can be: |
| * <ul> |
| * <li>major<<16 + minor : see predefined constants on ClassFileConstants </li> |
| * <li><code>0</null> if the root is a source package fragment root or if a Java model exception occured</li> |
| * </ul> |
| * Returns the jdk level |
| */ |
| public static long getJdkLevel(Object targetLibrary) { |
| try { |
| ClassFileReader reader = null; |
| if (targetLibrary instanceof IFolder) { |
| IFile classFile = findFirstClassFile((IFolder) targetLibrary); // only internal classfolders are allowed |
| if (classFile != null) |
| reader = Util.newClassFileReader(classFile); |
| } else { |
| // root is a jar file or a zip file |
| ZipFile jar = null; |
| try { |
| IPath path = null; |
| if (targetLibrary instanceof IResource) { |
| path = ((IResource)targetLibrary).getFullPath(); |
| } else if (targetLibrary instanceof File){ |
| File f = (File) targetLibrary; |
| if (!f.isDirectory()) { |
| path = new Path(((File)targetLibrary).getPath()); |
| } |
| } |
| if (path != null) { |
| jar = JavaModelManager.getJavaModelManager().getZipFile(path); |
| for (Enumeration e= jar.entries(); e.hasMoreElements();) { |
| ZipEntry member= (ZipEntry) e.nextElement(); |
| String entryName= member.getName(); |
| if (org.aspectj.org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(entryName)) { |
| reader = ClassFileReader.read(jar, entryName); |
| break; |
| } |
| } |
| } |
| } catch (CoreException e) { |
| // ignore |
| } finally { |
| JavaModelManager.getJavaModelManager().closeZipFile(jar); |
| } |
| } |
| if (reader != null) { |
| return reader.getVersion(); |
| } |
| } catch (CoreException e) { |
| // ignore |
| } catch(ClassFormatException e) { |
| // ignore |
| } catch(IOException e) { |
| // ignore |
| } |
| return 0; |
| } |
| |
| /** |
| * Returns the substring of the given file name, ending at the start of a |
| * Java like extension. The entire file name is returned if it doesn't end |
| * with a Java like extension. |
| */ |
| public static String getNameWithoutJavaLikeExtension(String fileName) { |
| int index = indexOfJavaLikeExtension(fileName); |
| if (index == -1) |
| return fileName; |
| return fileName.substring(0, index); |
| } |
| |
| /** |
| * Returns the line separator found in the given text. |
| * If it is null, or not found return the line delimiter for the given project. |
| * If the project is null, returns the line separator for the workspace. |
| * If still null, return the system line separator. |
| */ |
| public static String getLineSeparator(String text, IJavaProject project) { |
| String lineSeparator = null; |
| |
| // line delimiter in given text |
| if (text != null && text.length() != 0) { |
| lineSeparator = findLineSeparator(text.toCharArray()); |
| if (lineSeparator != null) |
| return lineSeparator; |
| } |
| |
| if (Platform.isRunning()) { |
| // line delimiter in project preference |
| IScopeContext[] scopeContext; |
| if (project != null) { |
| scopeContext= new IScopeContext[] { new ProjectScope(project.getProject()) }; |
| lineSeparator= Platform.getPreferencesService().getString(Platform.PI_RUNTIME, Platform.PREF_LINE_SEPARATOR, null, scopeContext); |
| if (lineSeparator != null) |
| return lineSeparator; |
| } |
| |
| // line delimiter in workspace preference |
| scopeContext= new IScopeContext[] { InstanceScope.INSTANCE }; |
| lineSeparator = Platform.getPreferencesService().getString(Platform.PI_RUNTIME, Platform.PREF_LINE_SEPARATOR, null, scopeContext); |
| if (lineSeparator != null) |
| return lineSeparator; |
| } |
| |
| // system line delimiter |
| return org.aspectj.org.eclipse.jdt.internal.compiler.util.Util.LINE_SEPARATOR; |
| } |
| |
| /** |
| * Returns the line separator used by the given buffer. |
| * Uses the given text if none found. |
| * |
| * @return </code>"\n"</code> or </code>"\r"</code> or </code>"\r\n"</code> |
| */ |
| private static String getLineSeparator(char[] text, char[] buffer) { |
| // search in this buffer's contents first |
| String lineSeparator = findLineSeparator(buffer); |
| if (lineSeparator == null) { |
| // search in the given text |
| lineSeparator = findLineSeparator(text); |
| if (lineSeparator == null) { |
| // default to system line separator |
| return getLineSeparator((String) null, (IJavaProject) null); |
| } |
| } |
| return lineSeparator; |
| } |
| |
| public static IPackageFragment getPackageFragment(char[] fileName, int pkgEnd, int jarSeparator) { |
| if (jarSeparator != -1) { |
| String jarMemento = new String(fileName, 0, jarSeparator); |
| PackageFragmentRoot root = (PackageFragmentRoot) JavaCore.create(jarMemento); |
| if (pkgEnd == jarSeparator) |
| return root.getPackageFragment(CharOperation.NO_STRINGS); |
| char[] pkgName = CharOperation.subarray(fileName, jarSeparator+1, pkgEnd); |
| char[][] compoundName = CharOperation.splitOn('/', pkgName); |
| return root.getPackageFragment(CharOperation.toStrings(compoundName)); |
| } else { |
| Path path = new Path(new String(fileName, 0, pkgEnd)); |
| IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); |
| IContainer folder = path.segmentCount() == 1 ? workspaceRoot.getProject(path.lastSegment()) : (IContainer) workspaceRoot.getFolder(path); |
| IJavaElement element = JavaCore.create(folder); |
| if (element == null) return null; |
| switch (element.getElementType()) { |
| case IJavaElement.PACKAGE_FRAGMENT: |
| return (IPackageFragment) element; |
| case IJavaElement.PACKAGE_FRAGMENT_ROOT: |
| return ((PackageFragmentRoot) element).getPackageFragment(CharOperation.NO_STRINGS); |
| case IJavaElement.JAVA_PROJECT: |
| PackageFragmentRoot root = (PackageFragmentRoot) ((IJavaProject) element).getPackageFragmentRoot(folder); |
| if (root == null) return null; |
| return root.getPackageFragment(CharOperation.NO_STRINGS); |
| } |
| return null; |
| } |
| } |
| |
| /** |
| * Returns the number of parameter types in a method signature. |
| */ |
| public static int getParameterCount(char[] sig) { |
| int i = CharOperation.indexOf('(', sig) + 1; |
| Assert.isTrue(i != 0); |
| int count = 0; |
| int len = sig.length; |
| for (;;) { |
| if (i == len) |
| break; |
| char c = sig[i]; |
| if (c == ')') |
| break; |
| if (c == '[') { |
| ++i; |
| } else |
| if (c == 'L') { |
| ++count; |
| i = CharOperation.indexOf(';', sig, i + 1) + 1; |
| Assert.isTrue(i != 0); |
| } else { |
| ++count; |
| ++i; |
| } |
| } |
| return count; |
| } |
| |
| /** |
| * Put all the arguments in one String. |
| */ |
| public static String getProblemArgumentsForMarker(String[] arguments){ |
| StringBuffer args = new StringBuffer(10); |
| |
| args.append(arguments.length); |
| args.append(':'); |
| |
| |
| for (int j = 0; j < arguments.length; j++) { |
| if(j != 0) |
| args.append(ARGUMENTS_DELIMITER); |
| |
| if(arguments[j].length() == 0) { |
| args.append(EMPTY_ARGUMENT); |
| } else { |
| encodeArgument(arguments[j], args); |
| } |
| } |
| |
| return args.toString(); |
| } |
| |
| /** |
| * Encode the argument by doubling the '#' if present into the argument value. |
| * |
| * <p>This stores the encoded argument into the given buffer.</p> |
| * |
| * @param argument the given argument |
| * @param buffer the buffer in which the encoded argument is stored |
| */ |
| private static void encodeArgument(String argument, StringBuffer buffer) { |
| for (int i = 0, max = argument.length(); i < max; i++) { |
| char charAt = argument.charAt(i); |
| switch(charAt) { |
| case ARGUMENTS_DELIMITER : |
| buffer.append(ARGUMENTS_DELIMITER).append(ARGUMENTS_DELIMITER); |
| break; |
| default: |
| buffer.append(charAt); |
| } |
| } |
| } |
| |
| /** |
| * Separate all the arguments of a String made by getProblemArgumentsForMarker |
| */ |
| public static String[] getProblemArgumentsFromMarker(String argumentsString){ |
| if (argumentsString == null) { |
| return null; |
| } |
| int index = argumentsString.indexOf(':'); |
| if(index == -1) |
| return null; |
| |
| int length = argumentsString.length(); |
| int numberOfArg = 0; |
| try{ |
| numberOfArg = Integer.parseInt(argumentsString.substring(0 , index)); |
| } catch (NumberFormatException e) { |
| return null; |
| } |
| argumentsString = argumentsString.substring(index + 1, length); |
| |
| return decodeArgumentString(numberOfArg, argumentsString); |
| } |
| |
| private static String[] decodeArgumentString(int length, String argumentsString) { |
| // decode the argumentString knowing that '#' is doubled if part of the argument value |
| if (length == 0) { |
| if (argumentsString.length() != 0) { |
| return null; |
| } |
| return CharOperation.NO_STRINGS; |
| } |
| String[] result = new String[length]; |
| int count = 0; |
| StringBuffer buffer = new StringBuffer(); |
| for (int i = 0, max = argumentsString.length(); i < max; i++) { |
| char current = argumentsString.charAt(i); |
| switch(current) { |
| case ARGUMENTS_DELIMITER : |
| /* check the next character. If this is also ARGUMENTS_DELIMITER then only put one into the |
| * decoded argument and proceed with the next character |
| */ |
| if ((i + 1) == max) { |
| return null; |
| } |
| char next = argumentsString.charAt(i + 1); |
| if (next == ARGUMENTS_DELIMITER) { |
| buffer.append(ARGUMENTS_DELIMITER); |
| i++; // proceed with the next character |
| } else { |
| // this means the current argument is over |
| String currentArgumentContents = String.valueOf(buffer); |
| if (EMPTY_ARGUMENT.equals(currentArgumentContents)) { |
| currentArgumentContents = org.aspectj.org.eclipse.jdt.internal.compiler.util.Util.EMPTY_STRING; |
| } |
| result[count++] = currentArgumentContents; |
| if (count > length) { |
| // too many elements - ill-formed |
| return null; |
| } |
| buffer.delete(0, buffer.length()); |
| } |
| break; |
| default : |
| buffer.append(current); |
| } |
| } |
| // process last argument |
| String currentArgumentContents = String.valueOf(buffer); |
| if (EMPTY_ARGUMENT.equals(currentArgumentContents)) { |
| currentArgumentContents = org.aspectj.org.eclipse.jdt.internal.compiler.util.Util.EMPTY_STRING; |
| } |
| result[count++] = currentArgumentContents; |
| if (count > length) { |
| // too many elements - ill-formed |
| return null; |
| } |
| buffer.delete(0, buffer.length()); |
| return result; |
| } |
| |
| /** |
| * Returns the given file's contents as a byte array. |
| */ |
| public static byte[] getResourceContentsAsByteArray(IFile file) throws JavaModelException { |
| InputStream stream= null; |
| try { |
| stream = file.getContents(true); |
| } catch (CoreException e) { |
| throw new JavaModelException(e); |
| } |
| try { |
| return org.aspectj.org.eclipse.jdt.internal.compiler.util.Util.getInputStreamAsByteArray(stream, -1); |
| } catch (IOException e) { |
| throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION); |
| } finally { |
| try { |
| stream.close(); |
| } catch (IOException e) { |
| // ignore |
| } |
| } |
| } |
| |
| /** |
| * Returns the given file's contents as a character array. |
| */ |
| public static char[] getResourceContentsAsCharArray(IFile file) throws JavaModelException { |
| // Get encoding from file |
| String encoding; |
| try { |
| encoding = file.getCharset(); |
| } catch(CoreException ce) { |
| // do not use any encoding |
| encoding = null; |
| } |
| return getResourceContentsAsCharArray(file, encoding); |
| } |
| |
| public static char[] getResourceContentsAsCharArray(IFile file, String encoding) throws JavaModelException { |
| // Get file length |
| // workaround https://bugs.eclipse.org/bugs/show_bug.cgi?id=130736 by using java.io.File if possible |
| IPath location = file.getLocation(); |
| long length; |
| if (location == null) { |
| // non local file |
| try { |
| URI locationURI = file.getLocationURI(); |
| if (locationURI == null) |
| throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, Messages.bind(Messages.file_notFound, file.getFullPath().toString()))); |
| length = EFS.getStore(locationURI).fetchInfo().getLength(); |
| } catch (CoreException e) { |
| throw new JavaModelException(e, IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST); |
| } |
| } else { |
| // local file |
| length = location.toFile().length(); |
| } |
| |
| // Get resource contents |
| InputStream stream= null; |
| try { |
| stream = file.getContents(true); |
| } catch (CoreException e) { |
| throw new JavaModelException(e, IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST); |
| } |
| try { |
| return org.aspectj.org.eclipse.jdt.internal.compiler.util.Util.getInputStreamAsCharArray(stream, (int) length, encoding); |
| } catch (IOException e) { |
| throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION); |
| } finally { |
| try { |
| stream.close(); |
| } catch (IOException e) { |
| // ignore |
| } |
| } |
| } |
| |
| /* |
| * Returns the signature of the given type. |
| */ |
| public static String getSignature(Type type) { |
| StringBuffer buffer = new StringBuffer(); |
| getFullyQualifiedName(type, buffer); |
| return Signature.createTypeSignature(buffer.toString(), false/*not resolved in source*/); |
| } |
| |
| /* |
| * Returns the source attachment property for this package fragment root's path |
| */ |
| public static String getSourceAttachmentProperty(IPath path) throws JavaModelException { |
| Map rootPathToAttachments = JavaModelManager.getJavaModelManager().rootPathToAttachments; |
| String property = (String) rootPathToAttachments.get(path); |
| if (property == null) { |
| try { |
| property = ResourcesPlugin.getWorkspace().getRoot().getPersistentProperty(getSourceAttachmentPropertyName(path)); |
| if (property == null) { |
| rootPathToAttachments.put(path, PackageFragmentRoot.NO_SOURCE_ATTACHMENT); |
| return null; |
| } |
| rootPathToAttachments.put(path, property); |
| return property; |
| } catch (CoreException e) { |
| throw new JavaModelException(e); |
| } |
| } else if (property.equals(PackageFragmentRoot.NO_SOURCE_ATTACHMENT)) { |
| return null; |
| } else |
| return property; |
| } |
| |
| private static QualifiedName getSourceAttachmentPropertyName(IPath path) { |
| return new QualifiedName(JavaCore.PLUGIN_ID, "sourceattachment: " + path.toOSString()); //$NON-NLS-1$ |
| } |
| |
| public static void setSourceAttachmentProperty(IPath path, String property) { |
| if (property == null) { |
| JavaModelManager.getJavaModelManager().rootPathToAttachments.put(path, PackageFragmentRoot.NO_SOURCE_ATTACHMENT); |
| } else { |
| JavaModelManager.getJavaModelManager().rootPathToAttachments.put(path, property); |
| } |
| try { |
| ResourcesPlugin.getWorkspace().getRoot().setPersistentProperty(getSourceAttachmentPropertyName(path), property); |
| } catch (CoreException e) { |
| e.printStackTrace(); |
| } |
| } |
| |
| /* |
| * Returns the declaring type signature of the element represented by the given binding key. |
| * Returns the signature of the element if it is a type. |
| * |
| * @return the declaring type signature |
| */ |
| public static String getDeclaringTypeSignature(String key) { |
| KeyToSignature keyToSignature = new KeyToSignature(key, KeyToSignature.DECLARING_TYPE); |
| keyToSignature.parse(); |
| return keyToSignature.signature.toString(); |
| } |
| |
| /* |
| * Appends to the given buffer the fully qualified name (as it appears in the source) of the given type |
| */ |
| private static void getFullyQualifiedName(Type type, StringBuffer buffer) { |
| switch (type.getNodeType()) { |
| case ASTNode.ARRAY_TYPE: |
| ArrayType arrayType = (ArrayType) type; |
| getFullyQualifiedName(arrayType.getElementType(), buffer); |
| for (int i = 0, length = arrayType.getDimensions(); i < length; i++) { |
| buffer.append('['); |
| buffer.append(']'); |
| } |
| break; |
| case ASTNode.PARAMETERIZED_TYPE: |
| ParameterizedType parameterizedType = (ParameterizedType) type; |
| getFullyQualifiedName(parameterizedType.getType(), buffer); |
| buffer.append('<'); |
| Iterator iterator = parameterizedType.typeArguments().iterator(); |
| boolean isFirst = true; |
| while (iterator.hasNext()) { |
| if (!isFirst) |
| buffer.append(','); |
| else |
| isFirst = false; |
| Type typeArgument = (Type) iterator.next(); |
| getFullyQualifiedName(typeArgument, buffer); |
| } |
| buffer.append('>'); |
| break; |
| case ASTNode.PRIMITIVE_TYPE: |
| buffer.append(((PrimitiveType) type).getPrimitiveTypeCode().toString()); |
| break; |
| case ASTNode.QUALIFIED_TYPE: |
| buffer.append(((QualifiedType) type).getName().getFullyQualifiedName()); |
| break; |
| case ASTNode.SIMPLE_TYPE: |
| buffer.append(((SimpleType) type).getName().getFullyQualifiedName()); |
| break; |
| case ASTNode.WILDCARD_TYPE: |
| buffer.append('?'); |
| WildcardType wildcardType = (WildcardType) type; |
| Type bound = wildcardType.getBound(); |
| if (bound == null) return; |
| if (wildcardType.isUpperBound()) { |
| buffer.append(" extends "); //$NON-NLS-1$ |
| } else { |
| buffer.append(" super "); //$NON-NLS-1$ |
| } |
| getFullyQualifiedName(bound, buffer); |
| break; |
| } |
| } |
| |
| /** |
| * Returns a trimmed version the simples names returned by Signature. |
| */ |
| public static String[] getTrimmedSimpleNames(String name) { |
| String[] result = Signature.getSimpleNames(name); |
| for (int i = 0, length = result.length; i < length; i++) { |
| result[i] = result[i].trim(); |
| } |
| return result; |
| } |
| |
| /** |
| * Return the java element corresponding to the given compiler binding. |
| */ |
| public static JavaElement getUnresolvedJavaElement(FieldBinding binding, WorkingCopyOwner workingCopyOwner, BindingsToNodesMap bindingsToNodes) { |
| if (binding.declaringClass == null) return null; // array length |
| JavaElement unresolvedJavaElement = getUnresolvedJavaElement(binding.declaringClass, workingCopyOwner, bindingsToNodes); |
| if (unresolvedJavaElement == null || unresolvedJavaElement.getElementType() != IJavaElement.TYPE) { |
| return null; |
| } |
| return (JavaElement) ((IType) unresolvedJavaElement).getField(String.valueOf(binding.name)); |
| } |
| |
| /** |
| * Returns the IInitializer that contains the given local variable in the given type |
| */ |
| public static JavaElement getUnresolvedJavaElement(int localSourceStart, int localSourceEnd, JavaElement type) { |
| try { |
| if (!(type instanceof IType)) |
| return null; |
| IInitializer[] initializers = ((IType) type).getInitializers(); |
| for (int i = 0; i < initializers.length; i++) { |
| IInitializer initializer = initializers[i]; |
| ISourceRange sourceRange = initializer.getSourceRange(); |
| if (sourceRange != null) { |
| int initializerStart = sourceRange.getOffset(); |
| int initializerEnd = initializerStart + sourceRange.getLength(); |
| if (initializerStart <= localSourceStart && localSourceEnd <= initializerEnd) { |
| return (JavaElement) initializer; |
| } |
| } |
| } |
| return null; |
| } catch (JavaModelException e) { |
| return null; |
| } |
| } |
| |
| /** |
| * Return the java element corresponding to the given compiler binding. |
| */ |
| public static JavaElement getUnresolvedJavaElement(MethodBinding methodBinding, WorkingCopyOwner workingCopyOwner, BindingsToNodesMap bindingsToNodes) { |
| JavaElement unresolvedJavaElement = getUnresolvedJavaElement(methodBinding.declaringClass, workingCopyOwner, bindingsToNodes); |
| if (unresolvedJavaElement == null || unresolvedJavaElement.getElementType() != IJavaElement.TYPE) { |
| return null; |
| } |
| IType declaringType = (IType) unresolvedJavaElement; |
| |
| org.aspectj.org.eclipse.jdt.internal.compiler.ast.ASTNode node = bindingsToNodes == null ? null : bindingsToNodes.get(methodBinding); |
| if (node != null && !declaringType.isBinary()) { |
| if (node instanceof AnnotationMethodDeclaration) { |
| // node is an AnnotationMethodDeclaration |
| AnnotationMethodDeclaration typeMemberDeclaration = (AnnotationMethodDeclaration) node; |
| return (JavaElement) declaringType.getMethod(String.valueOf(typeMemberDeclaration.selector), CharOperation.NO_STRINGS); // annotation type members don't have parameters |
| } else { |
| // node is an MethodDeclaration |
| MethodDeclaration methodDeclaration = (MethodDeclaration) node; |
| |
| Argument[] arguments = methodDeclaration.arguments; |
| String[] parameterSignatures; |
| if (arguments != null) { |
| parameterSignatures = new String[arguments.length]; |
| for (int i = 0; i < arguments.length; i++) { |
| Argument argument = arguments[i]; |
| TypeReference typeReference = argument.type; |
| int arrayDim = typeReference.dimensions(); |
| |
| String typeSig = |
| Signature.createTypeSignature( |
| CharOperation.concatWith( |
| typeReference.getTypeName(), '.'), false); |
| if (arrayDim > 0) { |
| typeSig = Signature.createArraySignature(typeSig, arrayDim); |
| } |
| parameterSignatures[i] = typeSig; |
| |
| } |
| } else { |
| parameterSignatures = CharOperation.NO_STRINGS; |
| } |
| return (JavaElement) declaringType.getMethod(String.valueOf(methodDeclaration.selector), parameterSignatures); |
| } |
| } else { |
| // case of method not in the created AST, or a binary method |
| org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodBinding original = methodBinding.original(); |
| String selector = original.isConstructor() ? declaringType.getElementName() : new String(original.selector); |
| boolean isBinary = declaringType.isBinary(); |
| ReferenceBinding enclosingType = original.declaringClass.enclosingType(); |
| // Static inner types' constructors don't get receivers (https://bugs.eclipse.org/bugs/show_bug.cgi?id=388137) |
| boolean isInnerBinaryTypeConstructor = isBinary && original.isConstructor() && !original.declaringClass.isStatic() && enclosingType != null; |
| TypeBinding[] parameters = original.parameters; |
| int length = parameters == null ? 0 : parameters.length; |
| int declaringIndex = isInnerBinaryTypeConstructor ? 1 : 0; |
| String[] parameterSignatures = new String[declaringIndex + length]; |
| if (isInnerBinaryTypeConstructor) |
| parameterSignatures[0] = new String(enclosingType.genericTypeSignature()).replace('/', '.'); |
| for (int i = 0; i < length; i++) { |
| char[] signature = parameters[i].genericTypeSignature(); |
| if (isBinary) { |
| signature = CharOperation.replaceOnCopy(signature, '/', '.'); |
| } else { |
| signature = toUnresolvedTypeSignature(signature); |
| } |
| parameterSignatures[declaringIndex + i] = new String(signature); |
| } |
| IMethod result = declaringType.getMethod(selector, parameterSignatures); |
| if (isBinary) |
| return (JavaElement) result; |
| if (result.exists()) // if perfect match (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=249567 ) |
| return (JavaElement) result; |
| IMethod[] methods = null; |
| try { |
| methods = declaringType.getMethods(); |
| } catch (JavaModelException e) { |
| // declaring type doesn't exist |
| return null; |
| } |
| IMethod[] candidates = Member.findMethods(result, methods); |
| if (candidates == null || candidates.length == 0) |
| return null; |
| return (JavaElement) candidates[0]; |
| } |
| } |
| |
| /** |
| * Return the java element corresponding to the given compiler binding. |
| */ |
| public static JavaElement getUnresolvedJavaElement(TypeBinding typeBinding, WorkingCopyOwner workingCopyOwner, BindingsToNodesMap bindingsToNodes) { |
| if (typeBinding == null) |
| return null; |
| switch (typeBinding.kind()) { |
| case Binding.ARRAY_TYPE : |
| typeBinding = ((org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ArrayBinding) typeBinding).leafComponentType(); |
| return getUnresolvedJavaElement(typeBinding, workingCopyOwner, bindingsToNodes); |
| case Binding.BASE_TYPE : |
| case Binding.WILDCARD_TYPE : |
| case Binding.INTERSECTION_TYPE: |
| return null; |
| default : |
| if (typeBinding.isCapture()) |
| return null; |
| } |
| ReferenceBinding referenceBinding; |
| if (typeBinding.isParameterizedType() || typeBinding.isRawType()) |
| referenceBinding = (ReferenceBinding) typeBinding.erasure(); |
| else |
| referenceBinding = (ReferenceBinding) typeBinding; |
| char[] fileName = referenceBinding.getFileName(); |
| if (referenceBinding.isLocalType() || referenceBinding.isAnonymousType()) { |
| // local or anonymous type |
| if (org.aspectj.org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(fileName)) { |
| int jarSeparator = CharOperation.indexOf(IDependent.JAR_FILE_ENTRY_SEPARATOR, fileName); |
| int pkgEnd = CharOperation.lastIndexOf('/', fileName); // pkgEnd is exclusive |
| if (pkgEnd == -1) |
| pkgEnd = CharOperation.lastIndexOf(File.separatorChar, fileName); |
| if (jarSeparator != -1 && pkgEnd < jarSeparator) // if in a jar and no slash, it is a default package -> pkgEnd should be equal to jarSeparator |
| pkgEnd = jarSeparator; |
| if (pkgEnd == -1) |
| return null; |
| IPackageFragment pkg = getPackageFragment(fileName, pkgEnd, jarSeparator); |
| char[] constantPoolName = referenceBinding.constantPoolName(); |
| if (constantPoolName == null) { |
| ClassFile classFile = (ClassFile) getClassFile(fileName); |
| return classFile == null ? null : (JavaElement) classFile.getType(); |
| } |
| pkgEnd = CharOperation.lastIndexOf('/', constantPoolName); |
| char[] classFileName = CharOperation.subarray(constantPoolName, pkgEnd+1, constantPoolName.length); |
| ClassFile classFile = (ClassFile) pkg.getClassFile(new String(classFileName) + SuffixConstants.SUFFIX_STRING_class); |
| return (JavaElement) classFile.getType(); |
| } |
| ICompilationUnit cu = getCompilationUnit(fileName, workingCopyOwner); |
| if (cu == null) return null; |
| // must use getElementAt(...) as there is no back pointer to the defining method (scope is null after resolution has ended) |
| try { |
| int sourceStart = ((org.aspectj.org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding) referenceBinding).sourceStart; |
| return (JavaElement) cu.getElementAt(sourceStart); |
| } catch (JavaModelException e) { |
| // does not exist |
| return null; |
| } |
| } else if (referenceBinding.isTypeVariable()) { |
| // type parameter |
| final String typeVariableName = new String(referenceBinding.sourceName()); |
| org.aspectj.org.eclipse.jdt.internal.compiler.lookup.Binding declaringElement = ((org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding) referenceBinding).declaringElement; |
| if (declaringElement instanceof MethodBinding) { |
| IMethod declaringMethod = (IMethod) getUnresolvedJavaElement((MethodBinding) declaringElement, workingCopyOwner, bindingsToNodes); |
| return (JavaElement) declaringMethod.getTypeParameter(typeVariableName); |
| } else { |
| IType declaringType = (IType) getUnresolvedJavaElement((TypeBinding) declaringElement, workingCopyOwner, bindingsToNodes); |
| return (JavaElement) declaringType.getTypeParameter(typeVariableName); |
| } |
| } else { |
| if (fileName == null) return null; // case of a WilCardBinding that doesn't have a corresponding Java element |
| // member or top level type |
| TypeBinding declaringTypeBinding = typeBinding.enclosingType(); |
| if (declaringTypeBinding == null) { |
| // top level type |
| if (org.aspectj.org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(fileName)) { |
| ClassFile classFile = (ClassFile) getClassFile(fileName); |
| if (classFile == null) return null; |
| return (JavaElement) classFile.getType(); |
| } |
| ICompilationUnit cu = getCompilationUnit(fileName, workingCopyOwner); |
| if (cu == null) return null; |
| return (JavaElement) cu.getType(new String(referenceBinding.sourceName())); |
| } else { |
| // member type |
| IType declaringType = (IType) getUnresolvedJavaElement(declaringTypeBinding, workingCopyOwner, bindingsToNodes); |
| if (declaringType == null) return null; |
| return (JavaElement) declaringType.getType(new String(referenceBinding.sourceName())); |
| } |
| } |
| } |
| |
| /* |
| * Returns the index of the most specific argument paths which is strictly enclosing the path to check |
| */ |
| public static int indexOfEnclosingPath(IPath checkedPath, IPath[] paths, int pathCount) { |
| |
| int bestMatch = -1, bestLength = -1; |
| for (int i = 0; i < pathCount; i++){ |
| if (paths[i].equals(checkedPath)) continue; |
| if (paths[i].isPrefixOf(checkedPath)) { |
| int currentLength = paths[i].segmentCount(); |
| if (currentLength > bestLength) { |
| bestLength = currentLength; |
| bestMatch = i; |
| } |
| } |
| } |
| return bestMatch; |
| } |
| |
| /* |
| * Returns the index of the Java like extension of the given file name |
| * or -1 if it doesn't end with a known Java like extension. |
| * Note this is the index of the '.' even if it is not considered part of the extension. |
| */ |
| public static int indexOfJavaLikeExtension(String fileName) { |
| int fileNameLength = fileName.length(); |
| char[][] javaLikeExtensions = getJavaLikeExtensions(); |
| extensions: for (int i = 0, length = javaLikeExtensions.length; i < length; i++) { |
| char[] extension = javaLikeExtensions[i]; |
| int extensionLength = extension.length; |
| int extensionStart = fileNameLength - extensionLength; |
| int dotIndex = extensionStart - 1; |
| if (dotIndex < 0) continue; |
| if (fileName.charAt(dotIndex) != '.') continue; |
| for (int j = 0; j < extensionLength; j++) { |
| if (fileName.charAt(extensionStart + j) != extension[j]) |
| continue extensions; |
| } |
| return dotIndex; |
| } |
| return -1; |
| } |
| |
| /* |
| * Returns the index of the first argument paths which is equal to the path to check |
| */ |
| public static int indexOfMatchingPath(IPath checkedPath, IPath[] paths, int pathCount) { |
| |
| for (int i = 0; i < pathCount; i++){ |
| if (paths[i].equals(checkedPath)) return i; |
| } |
| return -1; |
| } |
| |
| /* |
| * Returns the index of the first argument paths which is strictly nested inside the path to check |
| */ |
| public static int indexOfNestedPath(IPath checkedPath, IPath[] paths, int pathCount) { |
| |
| for (int i = 0; i < pathCount; i++){ |
| if (checkedPath.equals(paths[i])) continue; |
| if (checkedPath.isPrefixOf(paths[i])) return i; |
| } |
| return -1; |
| } |
| /** |
| * Returns whether the local file system supports accessing and modifying |
| * the given attribute. |
| */ |
| protected static boolean isAttributeSupported(int attribute) { |
| return (EFS.getLocalFileSystem().attributes() & attribute) != 0; |
| } |
| |
| /** |
| * Returns whether the given resource is read-only or not. |
| * @param resource |
| * @return <code>true</code> if the resource is read-only, <code>false</code> if it is not or |
| * if the file system does not support the read-only attribute. |
| */ |
| public static boolean isReadOnly(IResource resource) { |
| if (isReadOnlySupported()) { |
| ResourceAttributes resourceAttributes = resource.getResourceAttributes(); |
| if (resourceAttributes == null) return false; // not supported on this platform for this resource |
| return resourceAttributes.isReadOnly(); |
| } |
| return false; |
| } |
| |
| /** |
| * Returns whether the local file system supports accessing and modifying |
| * the read only flag. |
| */ |
| public static boolean isReadOnlySupported() { |
| return isAttributeSupported(EFS.ATTRIBUTE_READ_ONLY); |
| } |
| |
| /* |
| * Returns whether the given java element is exluded from its root's classpath. |
| * It doesn't check whether the root itself is on the classpath or not |
| */ |
| public static final boolean isExcluded(IJavaElement element) { |
| int elementType = element.getElementType(); |
| switch (elementType) { |
| case IJavaElement.JAVA_MODEL: |
| case IJavaElement.JAVA_PROJECT: |
| case IJavaElement.PACKAGE_FRAGMENT_ROOT: |
| return false; |
| |
| case IJavaElement.PACKAGE_FRAGMENT: |
| PackageFragmentRoot root = (PackageFragmentRoot) element.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT); |
| IResource resource = ((PackageFragment) element).resource(); |
| return resource != null && isExcluded(resource, root.fullInclusionPatternChars(), root.fullExclusionPatternChars()); |
| |
| case IJavaElement.COMPILATION_UNIT: |
| root = (PackageFragmentRoot) element.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT); |
| resource = element.getResource(); |
| if (resource == null) |
| return false; |
| if (isExcluded(resource, root.fullInclusionPatternChars(), root.fullExclusionPatternChars())) |
| return true; |
| return isExcluded(element.getParent()); |
| |
| default: |
| IJavaElement cu = element.getAncestor(IJavaElement.COMPILATION_UNIT); |
| return cu != null && isExcluded(cu); |
| } |
| } |
| /* |
| * Returns whether the given resource path matches one of the inclusion/exclusion |
| * patterns. |
| * NOTE: should not be asked directly using pkg root pathes |
| * @see IClasspathEntry#getInclusionPatterns |
| * @see IClasspathEntry#getExclusionPatterns |
| */ |
| public final static boolean isExcluded(IPath resourcePath, char[][] inclusionPatterns, char[][] exclusionPatterns, boolean isFolderPath) { |
| if (inclusionPatterns == null && exclusionPatterns == null) return false; |
| return org.aspectj.org.eclipse.jdt.internal.compiler.util.Util.isExcluded(resourcePath.toString().toCharArray(), inclusionPatterns, exclusionPatterns, isFolderPath); |
| } |
| |
| /* |
| * Returns whether the given resource matches one of the exclusion patterns. |
| * NOTE: should not be asked directly using pkg root pathes |
| * @see IClasspathEntry#getExclusionPatterns |
| */ |
| public final static boolean isExcluded(IResource resource, char[][] inclusionPatterns, char[][] exclusionPatterns) { |
| IPath path = resource.getFullPath(); |
| // ensure that folders are only excluded if all of their children are excluded |
| int resourceType = resource.getType(); |
| return isExcluded(path, inclusionPatterns, exclusionPatterns, resourceType == IResource.FOLDER || resourceType == IResource.PROJECT); |
| } |
| |
| |
| /** |
| * Validate the given .class file name. |
| * A .class file name must obey the following rules: |
| * <ul> |
| * <li> it must not be null |
| * <li> it must include the <code>".class"</code> suffix |
| * <li> its prefix must be a valid identifier |
| * </ul> |
| * </p> |
| * @param name the name of a .class file |
| * @param sourceLevel the source level |
| * @param complianceLevel the compliance level |
| * @return a status object with code <code>IStatus.OK</code> if |
| * the given name is valid as a .class file name, otherwise a status |
| * object indicating what is wrong with the name |
| */ |
| public static boolean isValidClassFileName(String name, String sourceLevel, String complianceLevel) { |
| return JavaConventions.validateClassFileName(name, sourceLevel, complianceLevel).getSeverity() != IStatus.ERROR; |
| } |
| |
| |
| /** |
| * Validate the given compilation unit name. |
| * A compilation unit name must obey the following rules: |
| * <ul> |
| * <li> it must not be null |
| * <li> it must include the <code>".java"</code> suffix |
| * <li> its prefix must be a valid identifier |
| * </ul> |
| * </p> |
| * @param name the name of a compilation unit |
| * @param sourceLevel the source level |
| * @param complianceLevel the compliance level |
| * @return a status object with code <code>IStatus.OK</code> if |
| * the given name is valid as a compilation unit name, otherwise a status |
| * object indicating what is wrong with the name |
| */ |
| public static boolean isValidCompilationUnitName(String name, String sourceLevel, String complianceLevel) { |
| return JavaConventions.validateCompilationUnitName(name, sourceLevel, complianceLevel).getSeverity() != IStatus.ERROR; |
| } |
| |
| /** |
| * Returns true if the given folder name is valid for a package, |
| * false if it is not. |
| * @param folderName the name of the folder |
| * @param sourceLevel the source level |
| * @param complianceLevel the compliance level |
| */ |
| public static boolean isValidFolderNameForPackage(String folderName, String sourceLevel, String complianceLevel) { |
| return JavaConventions.validateIdentifier(folderName, sourceLevel, complianceLevel).getSeverity() != IStatus.ERROR; |
| } |
| |
| /** |
| * Returns true if the given method signature is valid, |
| * false if it is not. |
| */ |
| public static boolean isValidMethodSignature(String sig) { |
| int len = sig.length(); |
| if (len == 0) return false; |
| int i = 0; |
| char c = sig.charAt(i++); |
| if (c != '(') return false; |
| if (i >= len) return false; |
| while (sig.charAt(i) != ')') { |
| // Void is not allowed as a parameter type. |
| i = checkTypeSignature(sig, i, len, false); |
| if (i == -1) return false; |
| if (i >= len) return false; |
| } |
| ++i; |
| i = checkTypeSignature(sig, i, len, true); |
| return i == len; |
| } |
| |
| /** |
| * Returns true if the given type signature is valid, |
| * false if it is not. |
| */ |
| public static boolean isValidTypeSignature(String sig, boolean allowVoid) { |
| int len = sig.length(); |
| return checkTypeSignature(sig, 0, len, allowVoid) == len; |
| } |
| |
| /* |
| * Returns the simple name of a local type from the given binary type name. |
| * The last '$' is at lastDollar. The last character of the type name is at end-1. |
| */ |
| public static String localTypeName(String binaryTypeName, int lastDollar, int end) { |
| if (lastDollar > 0 && binaryTypeName.charAt(lastDollar-1) == '$') |
| // local name starts with a dollar sign |
| // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=103466) |
| return binaryTypeName; |
| int nameStart = lastDollar+1; |
| while (nameStart < end && Character.isDigit(binaryTypeName.charAt(nameStart))) |
| nameStart++; |
| return binaryTypeName.substring(nameStart, end); |
| } |
| |
| /* |
| * Add a log entry |
| */ |
| public static void log(Throwable e, String message) { |
| Throwable nestedException; |
| if (e instanceof JavaModelException |
| && (nestedException = ((JavaModelException)e).getException()) != null) { |
| e = nestedException; |
| } |
| log(new Status( |
| IStatus.ERROR, |
| JavaCore.PLUGIN_ID, |
| IStatus.ERROR, |
| message, |
| e)); |
| } |
| |
| /** |
| * Log a message that is potentially repeated in the same session. |
| * The first time this method is called with a given exception, the |
| * exception stack trace is written to the log. |
| * <p>Only intended for use in debug statements.</p> |
| * |
| * @param key the given key |
| * @param e the given exception |
| * @throws IllegalArgumentException if the given key is null |
| */ |
| public static void logRepeatedMessage(String key, Exception e) { |
| if (key == null) { |
| throw new IllegalArgumentException("key cannot be null"); //$NON-NLS-1$ |
| } |
| if (fgRepeatedMessages.contains(key)) { |
| return; |
| } |
| fgRepeatedMessages.add(key); |
| log(e); |
| } |
| |
| public static void logRepeatedMessage(String key, int statusErrorID, String message) { |
| if (key == null) { |
| throw new IllegalArgumentException("key cannot be null"); //$NON-NLS-1$ |
| } |
| if (fgRepeatedMessages.contains(key)) { |
| return; |
| } |
| fgRepeatedMessages.add(key); |
| log(statusErrorID, message); |
| } |
| |
| /* |
| * Add a log entry |
| */ |
| public static void log(int statusErrorID, String message) { |
| log(new Status( |
| statusErrorID, |
| JavaCore.PLUGIN_ID, |
| message)); |
| } |
| |
| /* |
| * Add a log entry |
| */ |
| public static void log(IStatus status) { |
| Plugin plugin = JavaCore.getPlugin(); |
| if (plugin == null) { |
| System.err.println(status.toString()); |
| } else { |
| plugin.getLog().log(status); |
| } |
| } |
| |
| public static void log(Throwable e) { |
| log(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, Messages.code_assist_internal_error, e)); |
| } |
| |
| public static ClassFileReader newClassFileReader(IResource resource) throws CoreException, ClassFormatException, IOException { |
| InputStream in = null; |
| try { |
| in = ((IFile) resource).getContents(true); |
| return ClassFileReader.read(in, resource.getFullPath().toString()); |
| } finally { |
| if (in != null) |
| in.close(); |
| } |
| } |
| |
| /** |
| * Normalizes the cariage returns in the given text. |
| * They are all changed to use the given buffer's line separator. |
| */ |
| public static char[] normalizeCRs(char[] text, char[] buffer) { |
| CharArrayBuffer result = new CharArrayBuffer(); |
| int lineStart = 0; |
| int length = text.length; |
| if (length == 0) return text; |
| String lineSeparator = getLineSeparator(text, buffer); |
| char nextChar = text[0]; |
| for (int i = 0; i < length; i++) { |
| char currentChar = nextChar; |
| nextChar = i < length-1 ? text[i+1] : ' '; |
| switch (currentChar) { |
| case '\n': |
| int lineLength = i-lineStart; |
| char[] line = new char[lineLength]; |
| System.arraycopy(text, lineStart, line, 0, lineLength); |
| result.append(line); |
| result.append(lineSeparator); |
| lineStart = i+1; |
| break; |
| case '\r': |
| lineLength = i-lineStart; |
| if (lineLength >= 0) { |
| line = new char[lineLength]; |
| System.arraycopy(text, lineStart, line, 0, lineLength); |
| result.append(line); |
| result.append(lineSeparator); |
| if (nextChar == '\n') { |
| nextChar = ' '; |
| lineStart = i+2; |
| } else { |
| // when line separator are mixed in the same file |
| // \r might not be followed by a \n. If not, we should increment |
| // lineStart by one and not by two. |
| lineStart = i+1; |
| } |
| } else { |
| // when line separator are mixed in the same file |
| // we need to prevent NegativeArraySizeException |
| lineStart = i+1; |
| } |
| break; |
| } |
| } |
| char[] lastLine; |
| if (lineStart > 0) { |
| int lastLineLength = length-lineStart; |
| if (lastLineLength > 0) { |
| lastLine = new char[lastLineLength]; |
| System.arraycopy(text, lineStart, lastLine, 0, lastLineLength); |
| result.append(lastLine); |
| } |
| return result.getContents(); |
| } |
| return text; |
| } |
| |
| /** |
| * Normalizes the carriage returns in the given text. |
| * They are all changed to use given buffer's line separator. |
| */ |
| public static String normalizeCRs(String text, String buffer) { |
| return new String(normalizeCRs(text.toCharArray(), buffer.toCharArray())); |
| } |
| |
| /** |
| * Converts the given relative path into a package name. |
| * Returns null if the path is not a valid package name. |
| * @param pkgPath the package path |
| * @param sourceLevel the source level |
| * @param complianceLevel the compliance level |
| */ |
| public static String packageName(IPath pkgPath, String sourceLevel, String complianceLevel) { |
| StringBuffer pkgName = new StringBuffer(IPackageFragment.DEFAULT_PACKAGE_NAME); |
| for (int j = 0, max = pkgPath.segmentCount(); j < max; j++) { |
| String segment = pkgPath.segment(j); |
| if (!isValidFolderNameForPackage(segment, sourceLevel, complianceLevel)) { |
| return null; |
| } |
| pkgName.append(segment); |
| if (j < pkgPath.segmentCount() - 1) { |
| pkgName.append("." ); //$NON-NLS-1$ |
| } |
| } |
| return pkgName.toString(); |
| } |
| |
| /** |
| * Returns the length of the common prefix between s1 and s2. |
| */ |
| public static int prefixLength(char[] s1, char[] s2) { |
| int len= 0; |
| int max= Math.min(s1.length, s2.length); |
| for (int i= 0; i < max && s1[i] == s2[i]; ++i) |
| ++len; |
| return len; |
| } |
| /** |
| * Returns the length of the common prefix between s1 and s2. |
| */ |
| public static int prefixLength(String s1, String s2) { |
| int len= 0; |
| int max= Math.min(s1.length(), s2.length()); |
| for (int i= 0; i < max && s1.charAt(i) == s2.charAt(i); ++i) |
| ++len; |
| return len; |
| } |
| private static void quickSort(char[][] list, int left, int right) { |
| int original_left= left; |
| int original_right= right; |
| char[] mid= list[left + (right - left) / 2]; |
| do { |
| while (compare(list[left], mid) < 0) { |
| left++; |
| } |
| while (compare(mid, list[right]) < 0) { |
| right--; |
| } |
| if (left <= right) { |
| char[] tmp= list[left]; |
| list[left]= list[right]; |
| list[right]= tmp; |
| left++; |
| right--; |
| } |
| } while (left <= right); |
| if (original_left < right) { |
| quickSort(list, original_left, right); |
| } |
| if (left < original_right) { |
| quickSort(list, left, original_right); |
| } |
| } |
| |
| /** |
| * Sort the comparable objects in the given collection. |
| */ |
| private static void quickSort(Comparable[] sortedCollection, int left, int right) { |
| int original_left = left; |
| int original_right = right; |
| Comparable mid = sortedCollection[ left + (right - left) / 2]; |
| do { |
| while (sortedCollection[left].compareTo(mid) < 0) { |
| left++; |
| } |
| while (mid.compareTo(sortedCollection[right]) < 0) { |
| right--; |
| } |
| if (left <= right) { |
| Comparable tmp = sortedCollection[left]; |
| sortedCollection[left] = sortedCollection[right]; |
| sortedCollection[right] = tmp; |
| left++; |
| right--; |
| } |
| } while (left <= right); |
| if (original_left < right) { |
| quickSort(sortedCollection, original_left, right); |
| } |
| if (left < original_right) { |
| quickSort(sortedCollection, left, original_right); |
| } |
| } |
| private static void quickSort(int[] list, int left, int right) { |
| int original_left= left; |
| int original_right= right; |
| int mid= list[left + (right - left) / 2]; |
| do { |
| while (list[left] < mid) { |
| left++; |
| } |
| while (mid < list[right]) { |
| right--; |
| } |
| if (left <= right) { |
| int tmp= list[left]; |
| list[left]= list[right]; |
| list[right]= tmp; |
| left++; |
| right--; |
| } |
| } while (left <= right); |
| if (original_left < right) { |
| quickSort(list, original_left, right); |
| } |
| if (left < original_right) { |
| quickSort(list, left, original_right); |
| } |
| } |
| |
| /** |
| * Sort the objects in the given collection using the given comparer. |
| */ |
| private static void quickSort(Object[] sortedCollection, int left, int right, Comparer comparer) { |
| int original_left = left; |
| int original_right = right; |
| Object mid = sortedCollection[ left + (right - left) / 2]; |
| do { |
| while (comparer.compare(sortedCollection[left], mid) < 0) { |
| left++; |
| } |
| while (comparer.compare(mid, sortedCollection[right]) < 0) { |
| right--; |
| } |
| if (left <= right) { |
| Object tmp = sortedCollection[left]; |
| sortedCollection[left] = sortedCollection[right]; |
| sortedCollection[right] = tmp; |
| left++; |
| right--; |
| } |
| } while (left <= right); |
| if (original_left < right) { |
| quickSort(sortedCollection, original_left, right, comparer); |
| } |
| if (left < original_right) { |
| quickSort(sortedCollection, left, original_right, comparer); |
| } |
| } |
| |
| /** |
| * Sort the strings in the given collection. |
| */ |
| private static void quickSort(String[] sortedCollection, int left, int right) { |
| int original_left = left; |
| int original_right = right; |
| String mid = sortedCollection[ left + (right - left) / 2]; |
| do { |
| while (sortedCollection[left].compareTo(mid) < 0) { |
| left++; |
| } |
| while (mid.compareTo(sortedCollection[right]) < 0) { |
| right--; |
| } |
| if (left <= right) { |
| String tmp = sortedCollection[left]; |
| sortedCollection[left] = sortedCollection[right]; |
| sortedCollection[right] = tmp; |
| left++; |
| right--; |
| } |
| } while (left <= right); |
| if (original_left < right) { |
| quickSort(sortedCollection, original_left, right); |
| } |
| if (left < original_right) { |
| quickSort(sortedCollection, left, original_right); |
| } |
| } |
| |
| /** |
| * Returns the toString() of the given full path minus the first given number of segments. |
| * The returned string is always a relative path (it has no leading slash) |
| */ |
| public static String relativePath(IPath fullPath, int skipSegmentCount) { |
| boolean hasTrailingSeparator = fullPath.hasTrailingSeparator(); |
| String[] segments = fullPath.segments(); |
| |
| // compute length |
| int length = 0; |
| int max = segments.length; |
| if (max > skipSegmentCount) { |
| for (int i1 = skipSegmentCount; i1 < max; i1++) { |
| length += segments[i1].length(); |
| } |
| //add the separator lengths |
| length += max - skipSegmentCount - 1; |
| } |
| if (hasTrailingSeparator) |
| length++; |
| |
| char[] result = new char[length]; |
| int offset = 0; |
| int len = segments.length - 1; |
| if (len >= skipSegmentCount) { |
| //append all but the last segment, with separators |
| for (int i = skipSegmentCount; i < len; i++) { |
| int size = segments[i].length(); |
| segments[i].getChars(0, size, result, offset); |
| offset += size; |
| result[offset++] = '/'; |
| } |
| //append the last segment |
| int size = segments[len].length(); |
| segments[len].getChars(0, size, result, offset); |
| offset += size; |
| } |
| if (hasTrailingSeparator) |
| result[offset++] = '/'; |
| return new String(result); |
| } |
| |
| /* |
| * Resets the list of Java-like extensions after a change in content-type. |
| */ |
| public static void resetJavaLikeExtensions() { |
| JAVA_LIKE_EXTENSIONS = null; |
| } |
| |
| /** |
| * Scans the given string for a type signature starting at the given index |
| * and returns the index of the last character. |
| * <pre> |
| * TypeSignature: |
| * | BaseTypeSignature |
| * | ArrayTypeSignature |
| * | ClassTypeSignature |
| * | TypeVariableSignature |
| * </pre> |
| * |
| * @param string the signature string |
| * @param start the 0-based character index of the first character |
| * @return the 0-based character index of the last character |
| * @exception IllegalArgumentException if this is not a type signature |
| */ |
| public static int scanTypeSignature(char[] string, int start) { |
| // this method is used in jdt.debug |
| return org.aspectj.org.eclipse.jdt.internal.compiler.util.Util.scanTypeSignature(string, start); |
| } |
| /** |
| * Return a new array which is the split of the given string using the given divider. The given end |
| * is exclusive and the given start is inclusive. |
| * <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li><pre> |
| * divider = 'b' |
| * string = "abbaba" |
| * start = 2 |
| * end = 5 |
| * result => { "", "a", "" } |
| * </pre> |
| * </li> |
| * </ol> |
| * |
| * @param divider the given divider |
| * @param string the given string |
| * @param start the given starting index |
| * @param end the given ending index |
| * @return a new array which is the split of the given string using the given divider |
| * @throws ArrayIndexOutOfBoundsException if start is lower than 0 or end is greater than the array length |
| */ |
| public static final String[] splitOn( |
| char divider, |
| String string, |
| int start, |
| int end) { |
| int length = string == null ? 0 : string.length(); |
| if (length == 0 || start > end) |
| return CharOperation.NO_STRINGS; |
| |
| int wordCount = 1; |
| for (int i = start; i < end; i++) |
| if (string.charAt(i) == divider) |
| wordCount++; |
| String[] split = new String[wordCount]; |
| int last = start, currentWord = 0; |
| for (int i = start; i < end; i++) { |
| if (string.charAt(i) == divider) { |
| split[currentWord++] = string.substring(last, i); |
| last = i + 1; |
| } |
| } |
| split[currentWord] = string.substring(last, end); |
| return split; |
| } |
| /** |
| * Sets or unsets the given resource as read-only in the file system. |
| * It's a no-op if the file system does not support the read-only attribute. |
| * |
| * @param resource The resource to set as read-only |
| * @param readOnly <code>true</code> to set it to read-only, |
| * <code>false</code> to unset |
| */ |
| public static void setReadOnly(IResource resource, boolean readOnly) { |
| if (isReadOnlySupported()) { |
| ResourceAttributes resourceAttributes = resource.getResourceAttributes(); |
| if (resourceAttributes == null) return; // not supported on this platform for this resource |
| resourceAttributes.setReadOnly(readOnly); |
| try { |
| resource.setResourceAttributes(resourceAttributes); |
| } catch (CoreException e) { |
| // ignore |
| } |
| } |
| } |
| public static void sort(char[][] list) { |
| if (list.length > 1) |
| quickSort(list, 0, list.length - 1); |
| } |
| |
| /** |
| * Sorts an array of Comparable objects in place. |
| */ |
| public static void sort(Comparable[] objects) { |
| if (objects.length > 1) |
| quickSort(objects, 0, objects.length - 1); |
| } |
| public static void sort(int[] list) { |
| if (list.length > 1) |
| quickSort(list, 0, list.length - 1); |
| } |
| |
| /** |
| * Sorts an array of objects in place. |
| * The given comparer compares pairs of items. |
| */ |
| public static void sort(Object[] objects, Comparer comparer) { |
| if (objects.length > 1) |
| quickSort(objects, 0, objects.length - 1, comparer); |
| } |
| |
| /** |
| * Sorts an array of strings in place using quicksort. |
| */ |
| public static void sort(String[] strings) { |
| if (strings.length > 1) |
| quickSort(strings, 0, strings.length - 1); |
| } |
| |
| /** |
| * Sorts an array of Comparable objects, returning a new array |
| * with the sorted items. The original array is left untouched. |
| */ |
| public static Comparable[] sortCopy(Comparable[] objects) { |
| int len = objects.length; |
| Comparable[] copy = new Comparable[len]; |
| System.arraycopy(objects, 0, copy, 0, len); |
| sort(copy); |
| return copy; |
| } |
| |
| /** |
| * Sorts an array of Java elements based on their toStringWithAncestors(), |
| * returning a new array with the sorted items. |
| * The original array is left untouched. |
| */ |
| public static IJavaElement[] sortCopy(IJavaElement[] elements) { |
| int len = elements.length; |
| IJavaElement[] copy = new IJavaElement[len]; |
| System.arraycopy(elements, 0, copy, 0, len); |
| sort(copy, new Comparer() { |
| public int compare(Object a, Object b) { |
| return ((JavaElement) a).toStringWithAncestors().compareTo(((JavaElement) b).toStringWithAncestors()); |
| } |
| }); |
| return copy; |
| } |
| |
| /** |
| * Sorts an array of Strings, returning a new array |
| * with the sorted items. The original array is left untouched. |
| */ |
| public static Object[] sortCopy(Object[] objects, Comparer comparer) { |
| int len = objects.length; |
| Object[] copy = new Object[len]; |
| System.arraycopy(objects, 0, copy, 0, len); |
| sort(copy, comparer); |
| return copy; |
| } |
| |
| /** |
| * Sorts an array of Strings, returning a new array |
| * with the sorted items. The original array is left untouched. |
| */ |
| public static String[] sortCopy(String[] objects) { |
| int len = objects.length; |
| String[] copy = new String[len]; |
| System.arraycopy(objects, 0, copy, 0, len); |
| sort(copy); |
| return copy; |
| } |
| |
| /* |
| * Returns whether the given compound name starts with the given prefix. |
| * Returns true if the n first elements of the prefix are equals and the last element of the |
| * prefix is a prefix of the corresponding element in the compound name. |
| */ |
| public static boolean startsWithIgnoreCase(String[] compoundName, String[] prefix, boolean partialMatch) { |
| int prefixLength = prefix.length; |
| int nameLength = compoundName.length; |
| if (prefixLength > nameLength) return false; |
| for (int i = 0; i < prefixLength - 1; i++) { |
| if (!compoundName[i].equalsIgnoreCase(prefix[i])) |
| return false; |
| } |
| return (partialMatch || prefixLength == nameLength) && compoundName[prefixLength-1].toLowerCase().startsWith(prefix[prefixLength-1].toLowerCase()); |
| } |
| |
| /** |
| * Converts a String[] to char[][]. |
| */ |
| public static char[][] toCharArrays(String[] a) { |
| int len = a.length; |
| if (len == 0) return CharOperation.NO_CHAR_CHAR; |
| char[][] result = new char[len][]; |
| for (int i = 0; i < len; ++i) { |
| result[i] = a[i].toCharArray(); |
| } |
| return result; |
| } |
| |
| /** |
| * Converts a String to char[][], where segments are separate by '.'. |
| */ |
| public static char[][] toCompoundChars(String s) { |
| int len = s.length(); |
| if (len == 0) { |
| return CharOperation.NO_CHAR_CHAR; |
| } |
| int segCount = 1; |
| for (int off = s.indexOf('.'); off != -1; off = s.indexOf('.', off + 1)) { |
| ++segCount; |
| } |
| char[][] segs = new char[segCount][]; |
| int start = 0; |
| for (int i = 0; i < segCount; ++i) { |
| int dot = s.indexOf('.', start); |
| int end = (dot == -1 ? s.length() : dot); |
| segs[i] = new char[end - start]; |
| s.getChars(start, end, segs[i], 0); |
| start = end + 1; |
| } |
| return segs; |
| } |
| |
| /* |
| * Converts the given URI to a local file. Use the existing file if the uri is on the local file system. |
| * Otherwise fetch it. |
| * Returns null if unable to fetch it. |
| */ |
| public static File toLocalFile(URI uri, IProgressMonitor monitor) throws CoreException { |
| IFileStore fileStore = EFS.getStore(uri); |
| File localFile = fileStore.toLocalFile(EFS.NONE, monitor); |
| if (localFile ==null) |
| // non local file system |
| localFile= fileStore.toLocalFile(EFS.CACHE, monitor); |
| return localFile; |
| } |
| /** |
| * Converts a char[][] to String, where segments are separated by '.'. |
| */ |
| public static String toString(char[][] c) { |
| StringBuffer sb = new StringBuffer(); |
| for (int i = 0, max = c.length; i < max; ++i) { |
| if (i != 0) sb.append('.'); |
| sb.append(c[i]); |
| } |
| return sb.toString(); |
| } |
| |
| /** |
| * Converts a char[][] and a char[] to String, where segments are separated by '.'. |
| */ |
| public static String toString(char[][] c, char[] d) { |
| if (c == null) return new String(d); |
| StringBuffer sb = new StringBuffer(); |
| for (int i = 0, max = c.length; i < max; ++i) { |
| sb.append(c[i]); |
| sb.append('.'); |
| } |
| sb.append(d); |
| return sb.toString(); |
| } |
| |
| /* |
| * Converts a char[][] to String[]. |
| */ |
| public static String[] toStrings(char[][] a) { |
| int len = a.length; |
| String[] result = new String[len]; |
| for (int i = 0; i < len; ++i) { |
| result[i] = new String(a[i]); |
| } |
| return result; |
| } |
| private static char[] toUnresolvedTypeSignature(char[] signature) { |
| int length = signature.length; |
| if (length <= 1) |
| return signature; |
| StringBuffer buffer = new StringBuffer(length); |
| toUnresolvedTypeSignature(signature, 0, length, buffer); |
| int bufferLength = buffer.length(); |
| char[] result = new char[bufferLength]; |
| buffer.getChars(0, bufferLength, result, 0); |
| return result; |
| } |
| |
| private static int toUnresolvedTypeSignature(char[] signature, int start, int length, StringBuffer buffer) { |
| if (signature[start] == Signature.C_RESOLVED) |
| buffer.append(Signature.C_UNRESOLVED); |
| else |
| buffer.append(signature[start]); |
| for (int i = start+1; i < length; i++) { |
| char c = signature[i]; |
| switch (c) { |
| case '/': |
| case Signature.C_DOLLAR: |
| buffer.append(Signature.C_DOT); |
| break; |
| case Signature.C_GENERIC_START: |
| buffer.append(Signature.C_GENERIC_START); |
| i = toUnresolvedTypeSignature(signature, i+1, length, buffer); |
| break; |
| case Signature.C_GENERIC_END: |
| buffer.append(Signature.C_GENERIC_END); |
| return i; |
| default: |
| buffer.append(c); |
| break; |
| } |
| } |
| return length; |
| } |
| private static void appendArrayTypeSignature(char[] string, int start, StringBuffer buffer, boolean compact) { |
| int length = string.length; |
| // need a minimum 2 char |
| if (start >= length - 1) { |
| throw new IllegalArgumentException(); |
| } |
| char c = string[start]; |
| if (c != Signature.C_ARRAY) { |
| throw new IllegalArgumentException(); |
| } |
| |
| int index = start; |
| c = string[++index]; |
| while(c == Signature.C_ARRAY) { |
| // need a minimum 2 char |
| if (index >= length - 1) { |
| throw new IllegalArgumentException(); |
| } |
| c = string[++index]; |
| } |
| |
| appendTypeSignature(string, index, buffer, compact); |
| |
| for(int i = 0, dims = index - start; i < dims; i++) { |
| buffer.append('[').append(']'); |
| } |
| } |
| private static void appendClassTypeSignature(char[] string, int start, StringBuffer buffer, boolean compact) { |
| char c = string[start]; |
| if (c != Signature.C_RESOLVED) { |
| return; |
| } |
| int p = start + 1; |
| int checkpoint = buffer.length(); |
| while (true) { |
| c = string[p]; |
| switch(c) { |
| case Signature.C_SEMICOLON : |
| // all done |
| return; |
| case Signature.C_DOT : |
| case '/' : |
| // erase package prefix |
| if (compact) { |
| buffer.setLength(checkpoint); |
| } else { |
| buffer.append('.'); |
| } |
| break; |
| case Signature.C_DOLLAR : |
| /** |
| * Convert '$' in resolved type signatures into '.'. |
| * NOTE: This assumes that the type signature is an inner type |
| * signature. This is true in most cases, but someone can define a |
| * non-inner type name containing a '$'. |
| */ |
| buffer.append('.'); |
| break; |
| default : |
| buffer.append(c); |
| } |
| p++; |
| } |
| } |
| static void appendTypeSignature(char[] string, int start, StringBuffer buffer, boolean compact) { |
| char c = string[start]; |
| switch (c) { |
| case Signature.C_ARRAY : |
| appendArrayTypeSignature(string, start, buffer, compact); |
| break; |
| case Signature.C_RESOLVED : |
| appendClassTypeSignature(string, start, buffer, compact); |
| break; |
| case Signature.C_TYPE_VARIABLE : |
| int e = org.aspectj.org.eclipse.jdt.internal.compiler.util.Util.scanTypeVariableSignature(string, start); |
| buffer.append(string, start + 1, e - start - 1); |
| break; |
| case Signature.C_BOOLEAN : |
| buffer.append(BOOLEAN); |
| break; |
| case Signature.C_BYTE : |
| buffer.append(BYTE); |
| break; |
| case Signature.C_CHAR : |
| buffer.append(CHAR); |
| break; |
| case Signature.C_DOUBLE : |
| buffer.append(DOUBLE); |
| break; |
| case Signature.C_FLOAT : |
| buffer.append(FLOAT); |
| break; |
| case Signature.C_INT : |
| buffer.append(INT); |
| break; |
| case Signature.C_LONG : |
| buffer.append(LONG); |
| break; |
| case Signature.C_SHORT : |
| buffer.append(SHORT); |
| break; |
| case Signature.C_VOID : |
| buffer.append(VOID); |
| break; |
| } |
| } |
| public static String toString(char[] declaringClass, char[] methodName, char[] methodSignature, boolean includeReturnType, boolean compact) { |
| final boolean isConstructor = CharOperation.equals(methodName, INIT); |
| int firstParen = CharOperation.indexOf(Signature.C_PARAM_START, methodSignature); |
| if (firstParen == -1) { |
| return ""; //$NON-NLS-1$ |
| } |
| |
| StringBuffer buffer = new StringBuffer(methodSignature.length + 10); |
| |
| // decode declaring class name |
| // it can be either an array signature or a type signature |
| if (declaringClass != null && declaringClass.length > 0) { |
| char[] declaringClassSignature = null; |
| if (declaringClass[0] == Signature.C_ARRAY) { |
| CharOperation.replace(declaringClass, '/', '.'); |
| declaringClassSignature = Signature.toCharArray(declaringClass); |
| } else { |
| CharOperation.replace(declaringClass, '/', '.'); |
| declaringClassSignature = declaringClass; |
| } |
| int lastIndexOfSlash = CharOperation.lastIndexOf('.', declaringClassSignature); |
| if (compact && lastIndexOfSlash != -1) { |
| buffer.append(declaringClassSignature, lastIndexOfSlash + 1, declaringClassSignature.length - lastIndexOfSlash - 1); |
| } else { |
| buffer.append(declaringClassSignature); |
| } |
| if (!isConstructor) { |
| buffer.append('.'); |
| } |
| } |
| |
| // selector |
| if (!isConstructor && methodName != null) { |
| buffer.append(methodName); |
| } |
| |
| // parameters |
| buffer.append('('); |
| char[][] pts = Signature.getParameterTypes(methodSignature); |
| for (int i = 0, max = pts.length; i < max; i++) { |
| appendTypeSignature(pts[i], 0 , buffer, compact); |
| if (i != pts.length - 1) { |
| buffer.append(','); |
| buffer.append(' '); |
| } |
| } |
| buffer.append(')'); |
| |
| if (!isConstructor) { |
| buffer.append(" : "); //$NON-NLS-1$ |
| // return type |
| if (includeReturnType) { |
| char[] rts = Signature.getReturnType(methodSignature); |
| appendTypeSignature(rts, 0 , buffer, compact); |
| } |
| } |
| return String.valueOf(buffer); |
| } |
| /* |
| * Returns the unresolved type parameter signatures of the given method |
| * e.g. {"QString;", "[int", "[[Qjava.util.Vector;"} |
| */ |
| public static String[] typeParameterSignatures(AbstractMethodDeclaration method) { |
| Argument[] args = method.arguments; |
| if (args != null) { |
| int length = args.length; |
| String[] signatures = new String[length]; |
| for (int i = 0; i < args.length; i++) { |
| Argument arg = args[i]; |
| signatures[i] = typeSignature(arg.type); |
| } |
| return signatures; |
| } |
| return CharOperation.NO_STRINGS; |
| } |
| |
| /* |
| * Returns the unresolved type signature of the given type reference, |
| * e.g. "QString;", "[int", "[[Qjava.util.Vector;" |
| */ |
| public static String typeSignature(TypeReference type) { |
| String signature = null; |
| if ((type.bits & org.aspectj.org.eclipse.jdt.internal.compiler.ast.ASTNode.IsUnionType) != 0) { |
| // special treatment for union type reference |
| UnionTypeReference unionTypeReference = (UnionTypeReference) type; |
| TypeReference[] typeReferences = unionTypeReference.typeReferences; |
| int length = typeReferences.length; |
| String[] typeSignatures = new String[length]; |
| for(int i = 0; i < length; i++) { |
| char[][] compoundName = typeReferences[i].getParameterizedTypeName(); |
| char[] typeName = CharOperation.concatWith(compoundName, '.'); |
| typeSignatures[i] = Signature.createTypeSignature(typeName, false/*don't resolve*/); |
| } |
| signature = Signature.createIntersectionTypeSignature(typeSignatures); |
| } else { |
| char[][] compoundName = type.getParameterizedTypeName(); |
| char[] typeName =CharOperation.concatWith(compoundName, '.'); |
| signature = Signature.createTypeSignature(typeName, false/*don't resolve*/); |
| } |
| return signature; |
| } |
| |
| /** |
| * Asserts that the given method signature is valid. |
| */ |
| public static void validateMethodSignature(String sig) { |
| Assert.isTrue(isValidMethodSignature(sig)); |
| } |
| |
| /** |
| * Asserts that the given type signature is valid. |
| */ |
| public static void validateTypeSignature(String sig, boolean allowVoid) { |
| Assert.isTrue(isValidTypeSignature(sig, allowVoid)); |
| } |
| public static void verbose(String log) { |
| verbose(log, System.out); |
| } |
| public static synchronized void verbose(String log, PrintStream printStream) { |
| int start = 0; |
| do { |
| int end = log.indexOf('\n', start); |
| printStream.print(Thread.currentThread()); |
| printStream.print(" "); //$NON-NLS-1$ |
| printStream.print(log.substring(start, end == -1 ? log.length() : end+1)); |
| start = end+1; |
| } while (start != 0); |
| printStream.println(); |
| } |
| |
| /** |
| * Returns true if the given name ends with one of the known java like extension. |
| * (implementation is not creating extra strings) |
| */ |
| public final static boolean isJavaLikeFileName(String name) { |
| if (name == null) return false; |
| return indexOfJavaLikeExtension(name) != -1; |
| } |
| |
| /** |
| * Returns true if the given name ends with one of the known java like extension. |
| * (implementation is not creating extra strings) |
| */ |
| public final static boolean isJavaLikeFileName(char[] fileName) { |
| if (fileName == null) return false; |
| int fileNameLength = fileName.length; |
| char[][] javaLikeExtensions = getJavaLikeExtensions(); |
| extensions: for (int i = 0, length = javaLikeExtensions.length; i < length; i++) { |
| char[] extension = javaLikeExtensions[i]; |
| int extensionLength = extension.length; |
| int extensionStart = fileNameLength - extensionLength; |
| if (extensionStart-1 < 0) continue; |
| if (fileName[extensionStart-1] != '.') continue; |
| for (int j = 0; j < extensionLength; j++) { |
| if (fileName[extensionStart + j] != extension[j]) |
| continue extensions; |
| } |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Get all type arguments from an array of signatures. |
| * |
| * Example: |
| * For following type X<Y<Z>,V<W>,U>.A<B> signatures is: |
| * [ |
| * ['L','X','<','L','Y','<','L','Z',';'>',';','L','V','<','L','W',';'>',';','L','U',';',>',';'], |
| * ['L','A','<','L','B',';','>',';'] |
| * ] |
| * @see #splitTypeLevelsSignature(String) |
| * Then, this method returns: |
| * [ |
| * [ |
| * ['L','Y','<','L','Z',';'>',';'], |
| * ['L','V','<','L','W',';'>',';'], |
| * ['L','U',';'] |
| * ], |
| * [ |
| * ['L','B',';'] |
| * ] |
| * ] |
| * |
| * @param typeSignatures Array of signatures (one per each type levels) |
| * @throws IllegalArgumentException If one of provided signature is malformed |
| * @return char[][][] Array of type arguments for each signature |
| */ |
| public final static char[][][] getAllTypeArguments(char[][] typeSignatures) { |
| if (typeSignatures == null) return null; |
| int length = typeSignatures.length; |
| char[][][] typeArguments = new char[length][][]; |
| for (int i=0; i<length; i++){ |
| typeArguments[i] = Signature.getTypeArguments(typeSignatures[i]); |
| } |
| return typeArguments; |
| } |
| public static IAnnotation getAnnotation(JavaElement parent, IBinaryAnnotation binaryAnnotation, String memberValuePairName) { |
| char[] typeName = org.aspectj.org.eclipse.jdt.core.Signature.toCharArray(CharOperation.replaceOnCopy(binaryAnnotation.getTypeName(), '/', '.')); |
| return new Annotation(parent, new String(typeName), memberValuePairName); |
| } |
| |
| public static Object getAnnotationMemberValue(JavaElement parent, MemberValuePair memberValuePair, Object binaryValue) { |
| if (binaryValue instanceof Constant) { |
| return getAnnotationMemberValue(memberValuePair, (Constant) binaryValue); |
| } else if (binaryValue instanceof IBinaryAnnotation) { |
| memberValuePair.valueKind = IMemberValuePair.K_ANNOTATION; |
| return getAnnotation(parent, (IBinaryAnnotation) binaryValue, memberValuePair.getMemberName()); |
| } else if (binaryValue instanceof ClassSignature) { |
| memberValuePair.valueKind = IMemberValuePair.K_CLASS; |
| char[] className = Signature.toCharArray(CharOperation.replaceOnCopy(((ClassSignature) binaryValue).getTypeName(), '/', '.')); |
| return new String(className); |
| } else if (binaryValue instanceof EnumConstantSignature) { |
| memberValuePair.valueKind = IMemberValuePair.K_QUALIFIED_NAME; |
| EnumConstantSignature enumConstant = (EnumConstantSignature) binaryValue; |
| char[] enumName = Signature.toCharArray(CharOperation.replaceOnCopy(enumConstant.getTypeName(), '/', '.')); |
| char[] qualifiedName = CharOperation.concat(enumName, enumConstant.getEnumConstantName(), '.'); |
| return new String(qualifiedName); |
| } else if (binaryValue instanceof Object[]) { |
| memberValuePair.valueKind = -1; // modified below by the first call to getMemberValue(...) |
| Object[] binaryValues = (Object[]) binaryValue; |
| int length = binaryValues.length; |
| Object[] values = new Object[length]; |
| for (int i = 0; i < length; i++) { |
| int previousValueKind = memberValuePair.valueKind; |
| Object value = getAnnotationMemberValue(parent, memberValuePair, binaryValues[i]); |
| if (previousValueKind != -1 && memberValuePair.valueKind != previousValueKind) { |
| // values are heterogeneous, value kind is thus unknown |
| memberValuePair.valueKind = IMemberValuePair.K_UNKNOWN; |
| } |
| if (value instanceof Annotation) { |
| Annotation annotation = (Annotation) value; |
| for (int j = 0; j < i; j++) { |
| if (annotation.equals(values[j])) { |
| annotation.occurrenceCount++; |
| } |
| } |
| } |
| values[i] = value; |
| } |
| if (memberValuePair.valueKind == -1) |
| memberValuePair.valueKind = IMemberValuePair.K_UNKNOWN; |
| return values; |
| } else { |
| memberValuePair.valueKind = IMemberValuePair.K_UNKNOWN; |
| return null; |
| } |
| } |
| |
| /* |
| * Creates a member value from the given constant, and sets the valueKind on the given memberValuePair |
| */ |
| public static Object getAnnotationMemberValue(MemberValuePair memberValuePair, Constant constant) { |
| if (constant == null) { |
| memberValuePair.valueKind = IMemberValuePair.K_UNKNOWN; |
| return null; |
| } |
| switch (constant.typeID()) { |
| case TypeIds.T_int : |
| memberValuePair.valueKind = IMemberValuePair.K_INT; |
| return new Integer(constant.intValue()); |
| case TypeIds.T_byte : |
| memberValuePair.valueKind = IMemberValuePair.K_BYTE; |
| return new Byte(constant.byteValue()); |
| case TypeIds.T_short : |
| memberValuePair.valueKind = IMemberValuePair.K_SHORT; |
| return new Short(constant.shortValue()); |
| case TypeIds.T_char : |
| memberValuePair.valueKind = IMemberValuePair.K_CHAR; |
| return new Character(constant.charValue()); |
| case TypeIds.T_float : |
| memberValuePair.valueKind = IMemberValuePair.K_FLOAT; |
| return new Float(constant.floatValue()); |
| case TypeIds.T_double : |
| memberValuePair.valueKind = IMemberValuePair.K_DOUBLE; |
| return new Double(constant.doubleValue()); |
| case TypeIds.T_boolean : |
| memberValuePair.valueKind = IMemberValuePair.K_BOOLEAN; |
| return Boolean.valueOf(constant.booleanValue()); |
| case TypeIds.T_long : |
| memberValuePair.valueKind = IMemberValuePair.K_LONG; |
| return new Long(constant.longValue()); |
| case TypeIds.T_JavaLangString : |
| memberValuePair.valueKind = IMemberValuePair.K_STRING; |
| return constant.stringValue(); |
| default: |
| memberValuePair.valueKind = IMemberValuePair.K_UNKNOWN; |
| return null; |
| } |
| } |
| |
| /* |
| * Creates a member value from the given constant in case of negative numerals, |
| * and sets the valueKind on the given memberValuePair |
| */ |
| public static Object getNegativeAnnotationMemberValue(MemberValuePair memberValuePair, Constant constant) { |
| if (constant == null) { |
| memberValuePair.valueKind = IMemberValuePair.K_UNKNOWN; |
| return null; |
| } |
| switch (constant.typeID()) { |
| case TypeIds.T_int : |
| memberValuePair.valueKind = IMemberValuePair.K_INT; |
| return new Integer(constant.intValue() * -1); |
| case TypeIds.T_float : |
| memberValuePair.valueKind = IMemberValuePair.K_FLOAT; |
| return new Float(constant.floatValue() * -1.0f); |
| case TypeIds.T_double : |
| memberValuePair.valueKind = IMemberValuePair.K_DOUBLE; |
| return new Double(constant.doubleValue() * -1.0); |
| case TypeIds.T_long : |
| memberValuePair.valueKind = IMemberValuePair.K_LONG; |
| return new Long(constant.longValue() * -1L); |
| default: |
| memberValuePair.valueKind = IMemberValuePair.K_UNKNOWN; |
| return null; |
| } |
| } |
| /** |
| * Split signatures of all levels from a type unique key. |
| * |
| * Example: |
| * For following type X<Y<Z>,V<W>,U>.A<B>, unique key is: |
| * "LX<LY<LZ;>;LV<LW;>;LU;>.LA<LB;>;" |
| * |
| * The return splitted signatures array is: |
| * [ |
| * ['L','X','<','L','Y','<','L','Z',';'>',';','L','V','<','L','W',';'>',';','L','U','>',';'], |
| * ['L','A','<','L','B',';','>',';'] |
| * |
| * @param typeSignature ParameterizedSourceType type signature |
| * @return char[][] Array of signatures for each level of given unique key |
| */ |
| public final static char[][] splitTypeLevelsSignature(String typeSignature) { |
| // In case of IJavaElement signature, replace '$' by '.' |
| char[] source = Signature.removeCapture(typeSignature.toCharArray()); |
| CharOperation.replace(source, '$', '.'); |
| |
| // Init counters and arrays |
| char[][] signatures = new char[10][]; |
| int signaturesCount = 0; |
| // int[] lengthes = new int [10]; |
| int paramOpening = 0; |
| |
| // Scan each signature character |
| for (int idx=0, ln = source.length; idx < ln; idx++) { |
| switch (source[idx]) { |
| case '>': |
| paramOpening--; |
| if (paramOpening == 0) { |
| if (signaturesCount == signatures.length) { |
| System.arraycopy(signatures, 0, signatures = new char[signaturesCount+10][], 0, signaturesCount); |
| } |
| } |
| break; |
| case '<': |
| paramOpening++; |
| break; |
| case '.': |
| if (paramOpening == 0) { |
| if (signaturesCount == signatures.length) { |
| System.arraycopy(signatures, 0, signatures = new char[signaturesCount+10][], 0, signaturesCount); |
| } |
| signatures[signaturesCount] = new char[idx+1]; |
| System.arraycopy(source, 0, signatures[signaturesCount], 0, idx); |
| signatures[signaturesCount][idx] = Signature.C_SEMICOLON; |
| signaturesCount++; |
| } |
| break; |
| case '/': |
| source[idx] = '.'; |
| break; |
| } |
| } |
| |
| // Resize signatures array |
| char[][] typeSignatures = new char[signaturesCount+1][]; |
| typeSignatures[0] = source; |
| for (int i=1, j=signaturesCount-1; i<=signaturesCount; i++, j--){ |
| typeSignatures[i] = signatures[j]; |
| } |
| return typeSignatures; |
| } |
| |
| /* |
| * Can throw IllegalArgumentException or ArrayIndexOutOfBoundsException |
| */ |
| public static String toAnchor(int startingIndex, char[] methodSignature, String methodName, boolean isVarArgs) { |
| try { |
| return new String(toAnchor(startingIndex, methodSignature, methodName.toCharArray(), isVarArgs)); |
| } catch(IllegalArgumentException e) { |
| return null; |
| } |
| } |
| public static char[] toAnchor(int startingIndex, char[] methodSignature, char[] methodName, boolean isVargArgs) { |
| int firstParen = CharOperation.indexOf(Signature.C_PARAM_START, methodSignature); |
| if (firstParen == -1) { |
| throw new IllegalArgumentException(); |
| } |
| |
| StringBuffer buffer = new StringBuffer(methodSignature.length + 10); |
| |
| // selector |
| if (methodName != null) { |
| buffer.append(methodName); |
| } |
| |
| // parameters |
| buffer.append('('); |
| char[][] pts = Signature.getParameterTypes(methodSignature); |
| for (int i = startingIndex, max = pts.length; i < max; i++) { |
| if (i == max - 1) { |
| appendTypeSignatureForAnchor(pts[i], 0 , buffer, isVargArgs); |
| } else { |
| appendTypeSignatureForAnchor(pts[i], 0 , buffer, false); |
| } |
| if (i != pts.length - 1) { |
| buffer.append(','); |
| buffer.append(' '); |
| } |
| } |
| buffer.append(')'); |
| char[] result = new char[buffer.length()]; |
| buffer.getChars(0, buffer.length(), result, 0); |
| return result; |
| } |
| |
| private static int appendTypeSignatureForAnchor(char[] string, int start, StringBuffer buffer, boolean isVarArgs) { |
| // need a minimum 1 char |
| if (start >= string.length) { |
| throw new IllegalArgumentException(); |
| } |
| char c = string[start]; |
| if (isVarArgs) { |
| switch (c) { |
| case Signature.C_ARRAY : |
| return appendArrayTypeSignatureForAnchor(string, start, buffer, true); |
| case Signature.C_RESOLVED : |
| case Signature.C_TYPE_VARIABLE : |
| case Signature.C_BOOLEAN : |
| case Signature.C_BYTE : |
| case Signature.C_CHAR : |
| case Signature.C_DOUBLE : |
| case Signature.C_FLOAT : |
| case Signature.C_INT : |
| case Signature.C_LONG : |
| case Signature.C_SHORT : |
| case Signature.C_VOID : |
| case Signature.C_STAR: |
| case Signature.C_EXTENDS: |
| case Signature.C_SUPER: |
| case Signature.C_CAPTURE: |
| default: |
| throw new IllegalArgumentException(); // a var args is an array type |
| } |
| } else { |
| switch (c) { |
| case Signature.C_ARRAY : |
| return appendArrayTypeSignatureForAnchor(string, start, buffer, false); |
| case Signature.C_RESOLVED : |
| return appendClassTypeSignatureForAnchor(string, start, buffer); |
| case Signature.C_TYPE_VARIABLE : |
| int e = org.aspectj.org.eclipse.jdt.internal.compiler.util.Util.scanTypeVariableSignature(string, start); |
| buffer.append(string, start + 1, e - start - 1); |
| return e; |
| case Signature.C_BOOLEAN : |
| buffer.append(BOOLEAN); |
| return start; |
| case Signature.C_BYTE : |
| buffer.append(BYTE); |
| return start; |
| case Signature.C_CHAR : |
| buffer.append(CHAR); |
| return start; |
| case Signature.C_DOUBLE : |
| buffer.append(DOUBLE); |
| return start; |
| case Signature.C_FLOAT : |
| buffer.append(FLOAT); |
| return start; |
| case Signature.C_INT : |
| buffer.append(INT); |
| return start; |
| case Signature.C_LONG : |
| buffer.append(LONG); |
| return start; |
| case Signature.C_SHORT : |
| buffer.append(SHORT); |
| return start; |
| case Signature.C_VOID : |
| buffer.append(VOID); |
| return start; |
| case Signature.C_CAPTURE : |
| return appendCaptureTypeSignatureForAnchor(string, start, buffer); |
| case Signature.C_STAR: |
| case Signature.C_EXTENDS: |
| case Signature.C_SUPER: |
| return appendTypeArgumentSignatureForAnchor(string, start, buffer); |
| default : |
| throw new IllegalArgumentException(); |
| } |
| } |
| } |
| private static int appendTypeArgumentSignatureForAnchor(char[] string, int start, StringBuffer buffer) { |
| // need a minimum 1 char |
| if (start >= string.length) { |
| throw new IllegalArgumentException(); |
| } |
| char c = string[start]; |
| switch(c) { |
| case Signature.C_STAR : |
| return start; |
| case Signature.C_EXTENDS : |
| return appendTypeSignatureForAnchor(string, start + 1, buffer, false); |
| case Signature.C_SUPER : |
| return appendTypeSignatureForAnchor(string, start + 1, buffer, false); |
| default : |
| return appendTypeSignatureForAnchor(string, start, buffer, false); |
| } |
| } |
| private static int appendCaptureTypeSignatureForAnchor(char[] string, int start, StringBuffer buffer) { |
| // need a minimum 2 char |
| if (start >= string.length - 1) { |
| throw new IllegalArgumentException(); |
| } |
| char c = string[start]; |
| if (c != Signature.C_CAPTURE) { |
| throw new IllegalArgumentException(); |
| } |
| return appendTypeArgumentSignatureForAnchor(string, start + 1, buffer); |
| } |
| private static int appendArrayTypeSignatureForAnchor(char[] string, int start, StringBuffer buffer, boolean isVarArgs) { |
| int length = string.length; |
| // need a minimum 2 char |
| if (start >= length - 1) { |
| throw new IllegalArgumentException(); |
| } |
| char c = string[start]; |
| if (c != Signature.C_ARRAY) { |
| throw new IllegalArgumentException(); |
| } |
| |
| int index = start; |
| c = string[++index]; |
| while(c == Signature.C_ARRAY) { |
| // need a minimum 2 char |
| if (index >= length - 1) { |
| throw new IllegalArgumentException(); |
| } |
| c = string[++index]; |
| } |
| |
| int e = appendTypeSignatureForAnchor(string, index, buffer, false); |
| |
| for(int i = 1, dims = index - start; i < dims; i++) { |
| buffer.append('[').append(']'); |
| } |
| |
| if (isVarArgs) { |
| buffer.append('.').append('.').append('.'); |
| } else { |
| buffer.append('[').append(']'); |
| } |
| return e; |
| } |
| private static int appendClassTypeSignatureForAnchor(char[] string, int start, StringBuffer buffer) { |
| // need a minimum 3 chars "Lx;" |
| if (start >= string.length - 2) { |
| throw new IllegalArgumentException(); |
| } |
| // must start in "L" or "Q" |
| char c = string[start]; |
| if (c != Signature.C_RESOLVED && c != Signature.C_UNRESOLVED) { |
| throw new IllegalArgumentException(); |
| } |
| int p = start + 1; |
| while (true) { |
| if (p >= string.length) { |
| throw new IllegalArgumentException(); |
| } |
| c = string[p]; |
| switch(c) { |
| case Signature.C_SEMICOLON : |
| // all done |
| return p; |
| case Signature.C_GENERIC_START : |
| int e = scanGenericEnd(string, p + 1); |
| // once we hit type arguments there are no more package prefixes |
| p = e; |
| break; |
| case Signature.C_DOT : |
| buffer.append('.'); |
| break; |
| case '/' : |
| buffer.append('/'); |
| break; |
| case Signature.C_DOLLAR : |
| // once we hit "$" there are no more package prefixes |
| /** |
| * Convert '$' in resolved type signatures into '.'. |
| * NOTE: This assumes that the type signature is an inner type |
| * signature. This is true in most cases, but someone can define a |
| * non-inner type name containing a '$'. |
| */ |
| buffer.append('.'); |
| break; |
| default : |
| buffer.append(c); |
| } |
| p++; |
| } |
| } |
| private static int scanGenericEnd(char[] string, int start) { |
| if (string[start] == Signature.C_GENERIC_END) { |
| return start; |
| } |
| int length = string.length; |
| int balance = 1; |
| start++; |
| while (start <= length) { |
| switch(string[start]) { |
| case Signature.C_GENERIC_END : |
| balance--; |
| if (balance == 0) { |
| return start; |
| } |
| break; |
| case Signature.C_GENERIC_START : |
| balance++; |
| break; |
| } |
| start++; |
| } |
| return start; |
| } |
| |
| /* |
| * This method adjusts the task tags and task priorities so that they have the same size |
| */ |
| public static void fixTaskTags(Map defaultOptionsMap) { |
| Object taskTagsValue = defaultOptionsMap.get(JavaCore.COMPILER_TASK_TAGS); |
| char[][] taskTags = null; |
| if (taskTagsValue instanceof String) { |
| taskTags = CharOperation.splitAndTrimOn(',', ((String) taskTagsValue).toCharArray()); |
| } |
| Object taskPrioritiesValue = defaultOptionsMap.get(JavaCore.COMPILER_TASK_PRIORITIES); |
| char[][] taskPriorities = null; |
| if (taskPrioritiesValue instanceof String) { |
| taskPriorities = CharOperation.splitAndTrimOn(',', ((String) taskPrioritiesValue).toCharArray()); |
| } |
| if (taskPriorities == null) { |
| if (taskTags != null) { |
| Util.logRepeatedMessage(TASK_PRIORITIES_PROBLEM, IStatus.ERROR, "Inconsistent values for taskTags (not null) and task priorities (null)"); //$NON-NLS-1$ |
| defaultOptionsMap.remove(JavaCore.COMPILER_TASK_TAGS); |
| } |
| return; |
| } else if (taskTags == null) { |
| Util.logRepeatedMessage(TASK_PRIORITIES_PROBLEM, IStatus.ERROR, "Inconsistent values for taskTags (null) and task priorities (not null)"); //$NON-NLS-1$ |
| defaultOptionsMap.remove(JavaCore.COMPILER_TASK_PRIORITIES); |
| return; |
| } |
| int taskTagsLength = taskTags.length; |
| int taskPrioritiesLength = taskPriorities.length; |
| if (taskTagsLength != taskPrioritiesLength) { |
| Util.logRepeatedMessage(TASK_PRIORITIES_PROBLEM, IStatus.ERROR, "Inconsistent values for taskTags and task priorities : length is different"); //$NON-NLS-1$ |
| if (taskTagsLength > taskPrioritiesLength) { |
| System.arraycopy(taskTags, 0, (taskTags = new char[taskPrioritiesLength][]), 0, taskPrioritiesLength); |
| defaultOptionsMap.put(JavaCore.COMPILER_TASK_TAGS, new String(CharOperation.concatWith(taskTags,','))); |
| } else { |
| System.arraycopy(taskPriorities, 0, (taskPriorities = new char[taskTagsLength][]), 0, taskTagsLength); |
| defaultOptionsMap.put(JavaCore.COMPILER_TASK_PRIORITIES, new String(CharOperation.concatWith(taskPriorities,','))); |
| } |
| } |
| } |
| /** |
| * Finds the IMethod element corresponding to the given selector, |
| * without creating a new dummy instance of a binary method. |
| * @param type the type in which the method is declared |
| * @param selector the method name |
| * @param paramTypeSignatures the type signatures of the method arguments |
| * @param isConstructor whether we're looking for a constructor |
| * @return an IMethod if found, otherwise null |
| * @throws JavaModelException |
| */ |
| public static IMethod findMethod(IType type, char[] selector, String[] paramTypeSignatures, boolean isConstructor) throws JavaModelException { |
| IMethod method = null; |
| int startingIndex = 0; |
| String[] args; |
| IType enclosingType = type.getDeclaringType(); |
| // If the method is a constructor of a non-static inner type, add the enclosing type as an |
| // additional parameter to the constructor |
| if (enclosingType != null |
| && isConstructor |
| && !Flags.isStatic(type.getFlags())) { |
| args = new String[paramTypeSignatures.length+1]; |
| startingIndex = 1; |
| args[0] = Signature.createTypeSignature(enclosingType.getFullyQualifiedName(), true); |
| } else { |
| args = new String[paramTypeSignatures.length]; |
| } |
| int length = args.length; |
| for(int i = startingIndex; i< length ; i++){ |
| args[i] = new String(paramTypeSignatures[i-startingIndex]); |
| } |
| method = type.getMethod(new String(selector), args); |
| |
| IMethod[] methods = type.findMethods(method); |
| if (methods != null && methods.length > 0) { |
| method = methods[0]; |
| } |
| return method; |
| } |
| } |