Source Code Cross Referenced for Util.java in  » IDE-Eclipse » jdt » org » eclipse » jdt » internal » core » util » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE Eclipse » jdt » org.eclipse.jdt.internal.core.util 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*******************************************************************************
0002:         * Copyright (c) 2000, 2007 IBM Corporation and others.
0003:         * All rights reserved. This program and the accompanying materials
0004:         * are made available under the terms of the Eclipse Public License v1.0
0005:         * which accompanies this distribution, and is available at
0006:         * http://www.eclipse.org/legal/epl-v10.html
0007:         *
0008:         * Contributors:
0009:         *     IBM Corporation - initial API and implementation
0010:         *******************************************************************************/package org.eclipse.jdt.internal.core.util;
0011:
0012:        import java.io.*;
0013:        import java.net.URI;
0014:        import java.util.*;
0015:        import java.util.zip.ZipEntry;
0016:        import java.util.zip.ZipFile;
0017:
0018:        import org.eclipse.core.filesystem.EFS;
0019:        import org.eclipse.core.filesystem.IFileStore;
0020:        import org.eclipse.core.resources.*;
0021:        import org.eclipse.core.runtime.*;
0022:        import org.eclipse.core.runtime.content.IContentType;
0023:        import org.eclipse.core.runtime.preferences.IScopeContext;
0024:        import org.eclipse.core.runtime.preferences.InstanceScope;
0025:        import org.eclipse.jdt.core.*;
0026:        import org.eclipse.jdt.core.compiler.CharOperation;
0027:        import org.eclipse.jdt.core.dom.ASTNode;
0028:        import org.eclipse.jdt.core.dom.ArrayType;
0029:        import org.eclipse.jdt.core.dom.ParameterizedType;
0030:        import org.eclipse.jdt.core.dom.PrimitiveType;
0031:        import org.eclipse.jdt.core.dom.QualifiedType;
0032:        import org.eclipse.jdt.core.dom.SimpleType;
0033:        import org.eclipse.jdt.core.dom.Type;
0034:        import org.eclipse.jdt.core.dom.WildcardType;
0035:        import org.eclipse.jdt.core.util.IClassFileAttribute;
0036:        import org.eclipse.jdt.core.util.IClassFileReader;
0037:        import org.eclipse.jdt.core.util.ICodeAttribute;
0038:        import org.eclipse.jdt.core.util.IFieldInfo;
0039:        import org.eclipse.jdt.core.util.IMethodInfo;
0040:        import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
0041:        import org.eclipse.jdt.internal.compiler.ast.Argument;
0042:        import org.eclipse.jdt.internal.compiler.ast.TypeReference;
0043:        import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
0044:        import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
0045:        import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
0046:        import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
0047:        import org.eclipse.jdt.internal.core.JavaElement;
0048:        import org.eclipse.jdt.internal.core.JavaModelManager;
0049:        import org.eclipse.jdt.internal.core.PackageFragmentRoot;
0050:        import org.eclipse.jface.text.BadLocationException;
0051:        import org.eclipse.text.edits.MalformedTreeException;
0052:        import org.eclipse.text.edits.TextEdit;
0053:
0054:        /**
0055:         * Provides convenient utility methods to other types in this package.
0056:         */
0057:        public class Util {
0058:
0059:            public interface Comparable {
0060:                /**
0061:                 * Returns 0 if this and c are equal, >0 if this is greater than c,
0062:                 * or <0 if this is less than c.
0063:                 */
0064:                int compareTo(Comparable c);
0065:            }
0066:
0067:            public interface Comparer {
0068:                /**
0069:                 * Returns 0 if a and b are equal, >0 if a is greater than b,
0070:                 * or <0 if a is less than b.
0071:                 */
0072:                int compare(Object a, Object b);
0073:            }
0074:
0075:            private static final String ARGUMENTS_DELIMITER = "#"; //$NON-NLS-1$
0076:
0077:            private static final String EMPTY_ARGUMENT = "   "; //$NON-NLS-1$
0078:
0079:            private static char[][] JAVA_LIKE_EXTENSIONS;
0080:            public static boolean ENABLE_JAVA_LIKE_EXTENSIONS = true;
0081:
0082:            private static final char[] BOOLEAN = "boolean".toCharArray(); //$NON-NLS-1$
0083:            private static final char[] BYTE = "byte".toCharArray(); //$NON-NLS-1$
0084:            private static final char[] CHAR = "char".toCharArray(); //$NON-NLS-1$
0085:            private static final char[] DOUBLE = "double".toCharArray(); //$NON-NLS-1$
0086:            private static final char[] FLOAT = "float".toCharArray(); //$NON-NLS-1$
0087:            private static final char[] INT = "int".toCharArray(); //$NON-NLS-1$
0088:            private static final char[] LONG = "long".toCharArray(); //$NON-NLS-1$
0089:            private static final char[] SHORT = "short".toCharArray(); //$NON-NLS-1$
0090:            private static final char[] VOID = "void".toCharArray(); //$NON-NLS-1$
0091:            private static final char[] INIT = "<init>".toCharArray(); //$NON-NLS-1$
0092:
0093:            private Util() {
0094:                // cannot be instantiated
0095:            }
0096:
0097:            /**
0098:             * Returns a new array adding the second array at the end of first array.
0099:             * It answers null if the first and second are null.
0100:             * If the first array is null or if it is empty, then a new array is created with second.
0101:             * If the second array is null, then the first array is returned.
0102:             * <br>
0103:             * <br>
0104:             * For example:
0105:             * <ol>
0106:             * <li><pre>
0107:             *    first = null
0108:             *    second = "a"
0109:             *    => result = {"a"}
0110:             * </pre>
0111:             * <li><pre>
0112:             *    first = {"a"}
0113:             *    second = null
0114:             *    => result = {"a"}
0115:             * </pre>
0116:             * </li>
0117:             * <li><pre>
0118:             *    first = {"a"}
0119:             *    second = {"b"}
0120:             *    => result = {"a", "b"}
0121:             * </pre>
0122:             * </li>
0123:             * </ol>
0124:             * 
0125:             * @param first the first array to concatenate
0126:             * @param second the array to add at the end of the first array
0127:             * @return a new array adding the second array at the end of first array, or null if the two arrays are null.
0128:             */
0129:            public static final String[] arrayConcat(String[] first,
0130:                    String second) {
0131:                if (second == null)
0132:                    return first;
0133:                if (first == null)
0134:                    return new String[] { second };
0135:
0136:                int length = first.length;
0137:                if (first.length == 0) {
0138:                    return new String[] { second };
0139:                }
0140:
0141:                String[] result = new String[length + 1];
0142:                System.arraycopy(first, 0, result, 0, length);
0143:                result[length] = second;
0144:                return result;
0145:            }
0146:
0147:            /**
0148:             * Checks the type signature in String sig, 
0149:             * starting at start and ending before end (end is not included).
0150:             * Returns the index of the character immediately after the signature if valid,
0151:             * or -1 if not valid.
0152:             */
0153:            private static int checkTypeSignature(String sig, int start,
0154:                    int end, boolean allowVoid) {
0155:                if (start >= end)
0156:                    return -1;
0157:                int i = start;
0158:                char c = sig.charAt(i++);
0159:                int nestingDepth = 0;
0160:                while (c == '[') {
0161:                    ++nestingDepth;
0162:                    if (i >= end)
0163:                        return -1;
0164:                    c = sig.charAt(i++);
0165:                }
0166:                switch (c) {
0167:                case 'B':
0168:                case 'C':
0169:                case 'D':
0170:                case 'F':
0171:                case 'I':
0172:                case 'J':
0173:                case 'S':
0174:                case 'Z':
0175:                    break;
0176:                case 'V':
0177:                    if (!allowVoid)
0178:                        return -1;
0179:                    // array of void is not allowed
0180:                    if (nestingDepth != 0)
0181:                        return -1;
0182:                    break;
0183:                case 'L':
0184:                    int semicolon = sig.indexOf(';', i);
0185:                    // Must have at least one character between L and ;
0186:                    if (semicolon <= i || semicolon >= end)
0187:                        return -1;
0188:                    i = semicolon + 1;
0189:                    break;
0190:                default:
0191:                    return -1;
0192:                }
0193:                return i;
0194:            }
0195:
0196:            /**
0197:             * Combines two hash codes to make a new one.
0198:             */
0199:            public static int combineHashCodes(int hashCode1, int hashCode2) {
0200:                return hashCode1 * 17 + hashCode2;
0201:            }
0202:
0203:            /**
0204:             * Compares two byte arrays.  
0205:             * 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.
0206:             * 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.
0207:             * Returns 0 if they are equal or both null.
0208:             */
0209:            public static int compare(byte[] a, byte[] b) {
0210:                if (a == b)
0211:                    return 0;
0212:                if (a == null)
0213:                    return -1;
0214:                if (b == null)
0215:                    return 1;
0216:                int len = Math.min(a.length, b.length);
0217:                for (int i = 0; i < len; ++i) {
0218:                    int diff = a[i] - b[i];
0219:                    if (diff != 0)
0220:                        return diff;
0221:                }
0222:                if (a.length > len)
0223:                    return 1;
0224:                if (b.length > len)
0225:                    return -1;
0226:                return 0;
0227:            }
0228:
0229:            /**
0230:             * Compares two strings lexicographically. 
0231:             * The comparison is based on the Unicode value of each character in
0232:             * the strings. 
0233:             *
0234:             * @return  the value <code>0</code> if the str1 is equal to str2;
0235:             *          a value less than <code>0</code> if str1
0236:             *          is lexicographically less than str2; 
0237:             *          and a value greater than <code>0</code> if str1 is
0238:             *          lexicographically greater than str2.
0239:             */
0240:            public static int compare(char[] str1, char[] str2) {
0241:                int len1 = str1.length;
0242:                int len2 = str2.length;
0243:                int n = Math.min(len1, len2);
0244:                int i = 0;
0245:                while (n-- != 0) {
0246:                    char c1 = str1[i];
0247:                    char c2 = str2[i++];
0248:                    if (c1 != c2) {
0249:                        return c1 - c2;
0250:                    }
0251:                }
0252:                return len1 - len2;
0253:            }
0254:
0255:            /**
0256:             * Concatenate two strings with a char in between.
0257:             * @see #concat(String, String)
0258:             */
0259:            public static String concat(String s1, char c, String s2) {
0260:                if (s1 == null)
0261:                    s1 = "null"; //$NON-NLS-1$
0262:                if (s2 == null)
0263:                    s2 = "null"; //$NON-NLS-1$
0264:                int l1 = s1.length();
0265:                int l2 = s2.length();
0266:                char[] buf = new char[l1 + 1 + l2];
0267:                s1.getChars(0, l1, buf, 0);
0268:                buf[l1] = c;
0269:                s2.getChars(0, l2, buf, l1 + 1);
0270:                return new String(buf);
0271:            }
0272:
0273:            /**
0274:             * Concatenate two strings.
0275:             * Much faster than using +, which:
0276:             * 		- creates a StringBuffer,
0277:             * 		- which is synchronized,
0278:             * 		- of default size, so the resulting char array is
0279:             *        often larger than needed.
0280:             * This implementation creates an extra char array, since the
0281:             * String constructor copies its argument, but there's no way around this.
0282:             */
0283:            public static String concat(String s1, String s2) {
0284:                if (s1 == null)
0285:                    s1 = "null"; //$NON-NLS-1$
0286:                if (s2 == null)
0287:                    s2 = "null"; //$NON-NLS-1$
0288:                int l1 = s1.length();
0289:                int l2 = s2.length();
0290:                char[] buf = new char[l1 + l2];
0291:                s1.getChars(0, l1, buf, 0);
0292:                s2.getChars(0, l2, buf, l1);
0293:                return new String(buf);
0294:            }
0295:
0296:            /**
0297:             * Returns the concatenation of the given array parts using the given separator between each part.
0298:             * <br>
0299:             * <br>
0300:             * For example:<br>
0301:             * <ol>
0302:             * <li><pre>
0303:             *    array = {"a", "b"}
0304:             *    separator = '.'
0305:             *    => result = "a.b"
0306:             * </pre>
0307:             * </li>
0308:             * <li><pre>
0309:             *    array = {}
0310:             *    separator = '.'
0311:             *    => result = ""
0312:             * </pre></li>
0313:             * </ol>
0314:             * 
0315:             * @param array the given array
0316:             * @param separator the given separator
0317:             * @return the concatenation of the given array parts using the given separator between each part
0318:             */
0319:            public static final String concatWith(String[] array, char separator) {
0320:                StringBuffer buffer = new StringBuffer();
0321:                for (int i = 0, length = array.length; i < length; i++) {
0322:                    buffer.append(array[i]);
0323:                    if (i < length - 1)
0324:                        buffer.append(separator);
0325:                }
0326:                return buffer.toString();
0327:            }
0328:
0329:            /**
0330:             * Returns the concatenation of the given array parts using the given separator between each
0331:             * part and appending the given name at the end.
0332:             * <br>
0333:             * <br>
0334:             * For example:<br>
0335:             * <ol>
0336:             * <li><pre>
0337:             *    name = "c"
0338:             *    array = { "a", "b" }
0339:             *    separator = '.'
0340:             *    => result = "a.b.c"
0341:             * </pre>
0342:             * </li>
0343:             * <li><pre>
0344:             *    name = null
0345:             *    array = { "a", "b" }
0346:             *    separator = '.'
0347:             *    => result = "a.b"
0348:             * </pre></li>
0349:             * <li><pre>
0350:             *    name = " c"
0351:             *    array = null
0352:             *    separator = '.'
0353:             *    => result = "c"
0354:             * </pre></li>
0355:             * </ol>
0356:             * 
0357:             * @param array the given array
0358:             * @param name the given name
0359:             * @param separator the given separator
0360:             * @return the concatenation of the given array parts using the given separator between each
0361:             * part and appending the given name at the end
0362:             */
0363:            public static final String concatWith(String[] array, String name,
0364:                    char separator) {
0365:
0366:                if (array == null || array.length == 0)
0367:                    return name;
0368:                if (name == null || name.length() == 0)
0369:                    return concatWith(array, separator);
0370:                StringBuffer buffer = new StringBuffer();
0371:                for (int i = 0, length = array.length; i < length; i++) {
0372:                    buffer.append(array[i]);
0373:                    buffer.append(separator);
0374:                }
0375:                buffer.append(name);
0376:                return buffer.toString();
0377:
0378:            }
0379:
0380:            /**
0381:             * Concatenate three strings.
0382:             * @see #concat(String, String)
0383:             */
0384:            public static String concat(String s1, String s2, String s3) {
0385:                if (s1 == null)
0386:                    s1 = "null"; //$NON-NLS-1$
0387:                if (s2 == null)
0388:                    s2 = "null"; //$NON-NLS-1$
0389:                if (s3 == null)
0390:                    s3 = "null"; //$NON-NLS-1$
0391:                int l1 = s1.length();
0392:                int l2 = s2.length();
0393:                int l3 = s3.length();
0394:                char[] buf = new char[l1 + l2 + l3];
0395:                s1.getChars(0, l1, buf, 0);
0396:                s2.getChars(0, l2, buf, l1);
0397:                s3.getChars(0, l3, buf, l1 + l2);
0398:                return new String(buf);
0399:            }
0400:
0401:            /**
0402:             * Converts a type signature from the IBinaryType representation to the DC representation.
0403:             */
0404:            public static String convertTypeSignature(char[] sig, int start,
0405:                    int length) {
0406:                return new String(sig, start, length).replace('/', '.');
0407:            }
0408:
0409:            /*
0410:             * Returns the default java extension (".java").
0411:             * To be used when the extension is not known.
0412:             */
0413:            public static String defaultJavaExtension() {
0414:                return SuffixConstants.SUFFIX_STRING_java;
0415:            }
0416:
0417:            /**
0418:             * Apply the given edit on the given string and return the updated string.
0419:             * Return the given string if anything wrong happen while applying the edit.
0420:             * 
0421:             * @param original the given string
0422:             * @param edit the given edit
0423:             * 
0424:             * @return the updated string
0425:             */
0426:            public final static String editedString(String original,
0427:                    TextEdit edit) {
0428:                if (edit == null) {
0429:                    return original;
0430:                }
0431:                SimpleDocument document = new SimpleDocument(original);
0432:                try {
0433:                    edit.apply(document, TextEdit.NONE);
0434:                    return document.get();
0435:                } catch (MalformedTreeException e) {
0436:                    e.printStackTrace();
0437:                } catch (BadLocationException e) {
0438:                    e.printStackTrace();
0439:                }
0440:                return original;
0441:            }
0442:
0443:            /**
0444:             * Returns true iff str.toLowerCase().endsWith(end.toLowerCase())
0445:             * implementation is not creating extra strings.
0446:             */
0447:            public final static boolean endsWithIgnoreCase(String str,
0448:                    String end) {
0449:
0450:                int strLength = str == null ? 0 : str.length();
0451:                int endLength = end == null ? 0 : end.length();
0452:
0453:                // return false if the string is smaller than the end.
0454:                if (endLength > strLength)
0455:                    return false;
0456:
0457:                // return false if any character of the end are
0458:                // not the same in lower case.
0459:                for (int i = 1; i <= endLength; i++) {
0460:                    if (ScannerHelper.toLowerCase(end.charAt(endLength - i)) != ScannerHelper
0461:                            .toLowerCase(str.charAt(strLength - i)))
0462:                        return false;
0463:                }
0464:
0465:                return true;
0466:            }
0467:
0468:            /**
0469:             * Compares two arrays using equals() on the elements.
0470:             * Neither can be null. Only the first len elements are compared.
0471:             * Return false if either array is shorter than len.
0472:             */
0473:            public static boolean equalArrays(Object[] a, Object[] b, int len) {
0474:                if (a == b)
0475:                    return true;
0476:                if (a.length < len || b.length < len)
0477:                    return false;
0478:                for (int i = 0; i < len; ++i) {
0479:                    if (a[i] == null) {
0480:                        if (b[i] != null)
0481:                            return false;
0482:                    } else {
0483:                        if (!a[i].equals(b[i]))
0484:                            return false;
0485:                    }
0486:                }
0487:                return true;
0488:            }
0489:
0490:            /**
0491:             * Compares two arrays using equals() on the elements.
0492:             * Either or both arrays may be null.
0493:             * Returns true if both are null.
0494:             * Returns false if only one is null.
0495:             * If both are arrays, returns true iff they have the same length and
0496:             * all elements are equal.
0497:             */
0498:            public static boolean equalArraysOrNull(int[] a, int[] b) {
0499:                if (a == b)
0500:                    return true;
0501:                if (a == null || b == null)
0502:                    return false;
0503:                int len = a.length;
0504:                if (len != b.length)
0505:                    return false;
0506:                for (int i = 0; i < len; ++i) {
0507:                    if (a[i] != b[i])
0508:                        return false;
0509:                }
0510:                return true;
0511:            }
0512:
0513:            /**
0514:             * Compares two arrays using equals() on the elements.
0515:             * Either or both arrays may be null.
0516:             * Returns true if both are null.
0517:             * Returns false if only one is null.
0518:             * If both are arrays, returns true iff they have the same length and
0519:             * all elements compare true with equals.
0520:             */
0521:            public static boolean equalArraysOrNull(Object[] a, Object[] b) {
0522:                if (a == b)
0523:                    return true;
0524:                if (a == null || b == null)
0525:                    return false;
0526:
0527:                int len = a.length;
0528:                if (len != b.length)
0529:                    return false;
0530:                // walk array from end to beginning as this optimizes package name cases 
0531:                // where the first part is always the same (e.g. org.eclipse.jdt)
0532:                for (int i = len - 1; i >= 0; i--) {
0533:                    if (a[i] == null) {
0534:                        if (b[i] != null)
0535:                            return false;
0536:                    } else {
0537:                        if (!a[i].equals(b[i]))
0538:                            return false;
0539:                    }
0540:                }
0541:                return true;
0542:            }
0543:
0544:            /**
0545:             * Compares two arrays using equals() on the elements.
0546:             * The arrays are first sorted.
0547:             * Either or both arrays may be null.
0548:             * Returns true if both are null.
0549:             * Returns false if only one is null.
0550:             * If both are arrays, returns true iff they have the same length and
0551:             * iff, after sorting both arrays, all elements compare true with equals.
0552:             * The original arrays are left untouched.
0553:             */
0554:            public static boolean equalArraysOrNullSortFirst(Comparable[] a,
0555:                    Comparable[] b) {
0556:                if (a == b)
0557:                    return true;
0558:                if (a == null || b == null)
0559:                    return false;
0560:                int len = a.length;
0561:                if (len != b.length)
0562:                    return false;
0563:                if (len >= 2) { // only need to sort if more than two items
0564:                    a = sortCopy(a);
0565:                    b = sortCopy(b);
0566:                }
0567:                for (int i = 0; i < len; ++i) {
0568:                    if (!a[i].equals(b[i]))
0569:                        return false;
0570:                }
0571:                return true;
0572:            }
0573:
0574:            /**
0575:             * Compares two String arrays using equals() on the elements.
0576:             * The arrays are first sorted.
0577:             * Either or both arrays may be null.
0578:             * Returns true if both are null.
0579:             * Returns false if only one is null.
0580:             * If both are arrays, returns true iff they have the same length and
0581:             * iff, after sorting both arrays, all elements compare true with equals.
0582:             * The original arrays are left untouched.
0583:             */
0584:            public static boolean equalArraysOrNullSortFirst(String[] a,
0585:                    String[] b) {
0586:                if (a == b)
0587:                    return true;
0588:                if (a == null || b == null)
0589:                    return false;
0590:                int len = a.length;
0591:                if (len != b.length)
0592:                    return false;
0593:                if (len >= 2) { // only need to sort if more than two items
0594:                    a = sortCopy(a);
0595:                    b = sortCopy(b);
0596:                }
0597:                for (int i = 0; i < len; ++i) {
0598:                    if (!a[i].equals(b[i]))
0599:                        return false;
0600:                }
0601:                return true;
0602:            }
0603:
0604:            /**
0605:             * Compares two objects using equals().
0606:             * Either or both array may be null.
0607:             * Returns true if both are null.
0608:             * Returns false if only one is null.
0609:             * Otherwise, return the result of comparing with equals().
0610:             */
0611:            public static boolean equalOrNull(Object a, Object b) {
0612:                if (a == b) {
0613:                    return true;
0614:                }
0615:                if (a == null || b == null) {
0616:                    return false;
0617:                }
0618:                return a.equals(b);
0619:            }
0620:
0621:            /*
0622:             * Returns whether the given file name equals to the given string ignoring the java like extension
0623:             * of the file name.
0624:             * Returns false if it is not a java like file name.
0625:             */
0626:            public static boolean equalsIgnoreJavaLikeExtension(
0627:                    String fileName, String string) {
0628:                int fileNameLength = fileName.length();
0629:                int stringLength = string.length();
0630:                if (fileNameLength < stringLength)
0631:                    return false;
0632:                for (int i = 0; i < stringLength; i++) {
0633:                    if (fileName.charAt(i) != string.charAt(i)) {
0634:                        return false;
0635:                    }
0636:                }
0637:                char[][] javaLikeExtensions = getJavaLikeExtensions();
0638:                suffixes: for (int i = 0, length = javaLikeExtensions.length; i < length; i++) {
0639:                    char[] suffix = javaLikeExtensions[i];
0640:                    int extensionStart = stringLength + 1;
0641:                    if (extensionStart + suffix.length != fileNameLength)
0642:                        continue;
0643:                    if (fileName.charAt(stringLength) != '.')
0644:                        continue;
0645:                    for (int j = extensionStart; j < fileNameLength; j++) {
0646:                        if (fileName.charAt(j) != suffix[j - extensionStart])
0647:                            continue suffixes;
0648:                    }
0649:                    return true;
0650:                }
0651:                return false;
0652:            }
0653:
0654:            /**
0655:             * Given a qualified name, extract the last component.
0656:             * If the input is not qualified, the same string is answered.
0657:             */
0658:            public static String extractLastName(String qualifiedName) {
0659:                int i = qualifiedName.lastIndexOf('.');
0660:                if (i == -1)
0661:                    return qualifiedName;
0662:                return qualifiedName.substring(i + 1);
0663:            }
0664:
0665:            /**
0666:             * Extracts the parameter types from a method signature.
0667:             */
0668:            public static String[] extractParameterTypes(char[] sig) {
0669:                int count = getParameterCount(sig);
0670:                String[] result = new String[count];
0671:                if (count == 0)
0672:                    return result;
0673:                int i = CharOperation.indexOf('(', sig) + 1;
0674:                count = 0;
0675:                int len = sig.length;
0676:                int start = i;
0677:                for (;;) {
0678:                    if (i == len)
0679:                        break;
0680:                    char c = sig[i];
0681:                    if (c == ')')
0682:                        break;
0683:                    if (c == '[') {
0684:                        ++i;
0685:                    } else if (c == 'L') {
0686:                        i = CharOperation.indexOf(';', sig, i + 1) + 1;
0687:                        Assert.isTrue(i != 0);
0688:                        result[count++] = convertTypeSignature(sig, start, i
0689:                                - start);
0690:                        start = i;
0691:                    } else {
0692:                        ++i;
0693:                        result[count++] = convertTypeSignature(sig, start, i
0694:                                - start);
0695:                        start = i;
0696:                    }
0697:                }
0698:                return result;
0699:            }
0700:
0701:            /**
0702:             * Extracts the return type from a method signature.
0703:             */
0704:            public static String extractReturnType(String sig) {
0705:                int i = sig.lastIndexOf(')');
0706:                Assert.isTrue(i != -1);
0707:                return sig.substring(i + 1);
0708:            }
0709:
0710:            private static IFile findFirstClassFile(IFolder folder) {
0711:                try {
0712:                    IResource[] members = folder.members();
0713:                    for (int i = 0, max = members.length; i < max; i++) {
0714:                        IResource member = members[i];
0715:                        if (member.getType() == IResource.FOLDER) {
0716:                            return findFirstClassFile((IFolder) member);
0717:                        } else if (org.eclipse.jdt.internal.compiler.util.Util
0718:                                .isClassFileName(member.getName())) {
0719:                            return (IFile) member;
0720:                        }
0721:                    }
0722:                } catch (CoreException e) {
0723:                    // ignore
0724:                }
0725:                return null;
0726:            }
0727:
0728:            /**
0729:             * Finds the first line separator used by the given text.
0730:             *
0731:             * @return </code>"\n"</code> or </code>"\r"</code> or  </code>"\r\n"</code>,
0732:             *			or <code>null</code> if none found
0733:             */
0734:            public static String findLineSeparator(char[] text) {
0735:                // find the first line separator
0736:                int length = text.length;
0737:                if (length > 0) {
0738:                    char nextChar = text[0];
0739:                    for (int i = 0; i < length; i++) {
0740:                        char currentChar = nextChar;
0741:                        nextChar = i < length - 1 ? text[i + 1] : ' ';
0742:                        switch (currentChar) {
0743:                        case '\n':
0744:                            return "\n"; //$NON-NLS-1$
0745:                        case '\r':
0746:                            return nextChar == '\n' ? "\r\n" : "\r"; //$NON-NLS-1$ //$NON-NLS-2$
0747:                        }
0748:                    }
0749:                }
0750:                // not found
0751:                return null;
0752:            }
0753:
0754:            public static IClassFileAttribute getAttribute(
0755:                    IClassFileReader classFileReader, char[] attributeName) {
0756:                IClassFileAttribute[] attributes = classFileReader
0757:                        .getAttributes();
0758:                for (int i = 0, max = attributes.length; i < max; i++) {
0759:                    if (CharOperation.equals(attributes[i].getAttributeName(),
0760:                            attributeName)) {
0761:                        return attributes[i];
0762:                    }
0763:                }
0764:                return null;
0765:            }
0766:
0767:            public static IClassFileAttribute getAttribute(
0768:                    ICodeAttribute codeAttribute, char[] attributeName) {
0769:                IClassFileAttribute[] attributes = codeAttribute
0770:                        .getAttributes();
0771:                for (int i = 0, max = attributes.length; i < max; i++) {
0772:                    if (CharOperation.equals(attributes[i].getAttributeName(),
0773:                            attributeName)) {
0774:                        return attributes[i];
0775:                    }
0776:                }
0777:                return null;
0778:            }
0779:
0780:            public static IClassFileAttribute getAttribute(
0781:                    IFieldInfo fieldInfo, char[] attributeName) {
0782:                IClassFileAttribute[] attributes = fieldInfo.getAttributes();
0783:                for (int i = 0, max = attributes.length; i < max; i++) {
0784:                    if (CharOperation.equals(attributes[i].getAttributeName(),
0785:                            attributeName)) {
0786:                        return attributes[i];
0787:                    }
0788:                }
0789:                return null;
0790:            }
0791:
0792:            public static IClassFileAttribute getAttribute(
0793:                    IMethodInfo methodInfo, char[] attributeName) {
0794:                IClassFileAttribute[] attributes = methodInfo.getAttributes();
0795:                for (int i = 0, max = attributes.length; i < max; i++) {
0796:                    if (CharOperation.equals(attributes[i].getAttributeName(),
0797:                            attributeName)) {
0798:                        return attributes[i];
0799:                    }
0800:                }
0801:                return null;
0802:            }
0803:
0804:            /**
0805:             * Returns the registered Java like extensions.
0806:             */
0807:            public static char[][] getJavaLikeExtensions() {
0808:                if (JAVA_LIKE_EXTENSIONS == null) {
0809:                    // TODO (jerome) reenable once JDT UI supports other file extensions (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=71460)
0810:                    if (!ENABLE_JAVA_LIKE_EXTENSIONS)
0811:                        JAVA_LIKE_EXTENSIONS = new char[][] { SuffixConstants.EXTENSION_java
0812:                                .toCharArray() };
0813:                    else {
0814:                        IContentType javaContentType = Platform
0815:                                .getContentTypeManager().getContentType(
0816:                                        JavaCore.JAVA_SOURCE_CONTENT_TYPE);
0817:                        HashSet fileExtensions = new HashSet();
0818:                        // content types derived from java content type should be included (https://bugs.eclipse.org/bugs/show_bug.cgi?id=121715)
0819:                        IContentType[] contentTypes = Platform
0820:                                .getContentTypeManager().getAllContentTypes();
0821:                        for (int i = 0, length = contentTypes.length; i < length; i++) {
0822:                            if (contentTypes[i].isKindOf(javaContentType)) { // note that javaContentType.isKindOf(javaContentType) == true
0823:                                String[] fileExtension = contentTypes[i]
0824:                                        .getFileSpecs(IContentType.FILE_EXTENSION_SPEC);
0825:                                for (int j = 0, length2 = fileExtension.length; j < length2; j++) {
0826:                                    fileExtensions.add(fileExtension[j]);
0827:                                }
0828:                            }
0829:                        }
0830:                        int length = fileExtensions.size();
0831:                        // note that file extensions contains "java" as it is defined in JDT Core's plugin.xml
0832:                        char[][] extensions = new char[length][];
0833:                        extensions[0] = SuffixConstants.EXTENSION_java
0834:                                .toCharArray(); // ensure that "java" is first
0835:                        int index = 1;
0836:                        Iterator iterator = fileExtensions.iterator();
0837:                        while (iterator.hasNext()) {
0838:                            String fileExtension = (String) iterator.next();
0839:                            if (SuffixConstants.EXTENSION_java
0840:                                    .equals(fileExtension))
0841:                                continue;
0842:                            extensions[index++] = fileExtension.toCharArray();
0843:                        }
0844:                        JAVA_LIKE_EXTENSIONS = extensions;
0845:                    }
0846:                }
0847:                return JAVA_LIKE_EXTENSIONS;
0848:            }
0849:
0850:            /**
0851:             * Get the jdk level of this root.
0852:             * The value can be:
0853:             * <ul>
0854:             * <li>major<<16 + minor : see predefined constants on ClassFileConstants </li>
0855:             * <li><code>0</null> if the root is a source package fragment root or if a Java model exception occured</li>
0856:             * </ul>
0857:             * Returns the jdk level
0858:             */
0859:            public static long getJdkLevel(Object targetLibrary) {
0860:                try {
0861:                    ClassFileReader reader = null;
0862:                    if (targetLibrary instanceof  IFolder) {
0863:                        IFile classFile = findFirstClassFile((IFolder) targetLibrary); // only internal classfolders are allowed
0864:                        if (classFile != null)
0865:                            reader = Util.newClassFileReader(classFile);
0866:                    } else {
0867:                        // root is a jar file or a zip file
0868:                        ZipFile jar = null;
0869:                        try {
0870:                            IPath path = null;
0871:                            if (targetLibrary instanceof  IResource) {
0872:                                path = ((IResource) targetLibrary)
0873:                                        .getFullPath();
0874:                            } else if (targetLibrary instanceof  File) {
0875:                                File f = (File) targetLibrary;
0876:                                if (!f.isDirectory()) {
0877:                                    path = new Path(((File) targetLibrary)
0878:                                            .getPath());
0879:                                }
0880:                            }
0881:                            if (path != null) {
0882:                                jar = JavaModelManager.getJavaModelManager()
0883:                                        .getZipFile(path);
0884:                                for (Enumeration e = jar.entries(); e
0885:                                        .hasMoreElements();) {
0886:                                    ZipEntry member = (ZipEntry) e
0887:                                            .nextElement();
0888:                                    String entryName = member.getName();
0889:                                    if (org.eclipse.jdt.internal.compiler.util.Util
0890:                                            .isClassFileName(entryName)) {
0891:                                        reader = ClassFileReader.read(jar,
0892:                                                entryName);
0893:                                        break;
0894:                                    }
0895:                                }
0896:                            }
0897:                        } catch (CoreException e) {
0898:                            // ignore
0899:                        } finally {
0900:                            JavaModelManager.getJavaModelManager()
0901:                                    .closeZipFile(jar);
0902:                        }
0903:                    }
0904:                    if (reader != null) {
0905:                        return reader.getVersion();
0906:                    }
0907:                } catch (CoreException e) {
0908:                    // ignore
0909:                } catch (ClassFormatException e) {
0910:                    // ignore
0911:                } catch (IOException e) {
0912:                    // ignore
0913:                }
0914:                return 0;
0915:            }
0916:
0917:            /**
0918:             * Returns the substring of the given file name, ending at the start of a
0919:             * Java like extension. The entire file name is returned if it doesn't end
0920:             * with a Java like extension.
0921:             */
0922:            public static String getNameWithoutJavaLikeExtension(String fileName) {
0923:                int index = indexOfJavaLikeExtension(fileName);
0924:                if (index == -1)
0925:                    return fileName;
0926:                return fileName.substring(0, index);
0927:            }
0928:
0929:            /**
0930:             * Returns the line separator found in the given text.
0931:             * If it is null, or not found return the line delimitor for the given project.
0932:             * If the project is null, returns the line separator for the workspace.
0933:             * If still null, return the system line separator.
0934:             */
0935:            public static String getLineSeparator(String text,
0936:                    IJavaProject project) {
0937:                String lineSeparator = null;
0938:
0939:                // line delimiter in given text
0940:                if (text != null && text.length() != 0) {
0941:                    lineSeparator = findLineSeparator(text.toCharArray());
0942:                    if (lineSeparator != null)
0943:                        return lineSeparator;
0944:                }
0945:
0946:                // line delimiter in project preference
0947:                IScopeContext[] scopeContext;
0948:                if (project != null) {
0949:                    scopeContext = new IScopeContext[] { new ProjectScope(
0950:                            project.getProject()) };
0951:                    lineSeparator = Platform.getPreferencesService().getString(
0952:                            Platform.PI_RUNTIME, Platform.PREF_LINE_SEPARATOR,
0953:                            null, scopeContext);
0954:                    if (lineSeparator != null)
0955:                        return lineSeparator;
0956:                }
0957:
0958:                // line delimiter in workspace preference
0959:                scopeContext = new IScopeContext[] { new InstanceScope() };
0960:                lineSeparator = Platform.getPreferencesService().getString(
0961:                        Platform.PI_RUNTIME, Platform.PREF_LINE_SEPARATOR,
0962:                        null, scopeContext);
0963:                if (lineSeparator != null)
0964:                    return lineSeparator;
0965:
0966:                // system line delimiter
0967:                return org.eclipse.jdt.internal.compiler.util.Util.LINE_SEPARATOR;
0968:            }
0969:
0970:            /**
0971:             * Returns the line separator used by the given buffer.
0972:             * Uses the given text if none found.
0973:             *
0974:             * @return </code>"\n"</code> or </code>"\r"</code> or  </code>"\r\n"</code>
0975:             */
0976:            private static String getLineSeparator(char[] text, char[] buffer) {
0977:                // search in this buffer's contents first
0978:                String lineSeparator = findLineSeparator(buffer);
0979:                if (lineSeparator == null) {
0980:                    // search in the given text
0981:                    lineSeparator = findLineSeparator(text);
0982:                    if (lineSeparator == null) {
0983:                        // default to system line separator
0984:                        return getLineSeparator((String) null,
0985:                                (IJavaProject) null);
0986:                    }
0987:                }
0988:                return lineSeparator;
0989:            }
0990:
0991:            /**
0992:             * Returns the number of parameter types in a method signature.
0993:             */
0994:            public static int getParameterCount(char[] sig) {
0995:                int i = CharOperation.indexOf('(', sig) + 1;
0996:                Assert.isTrue(i != 0);
0997:                int count = 0;
0998:                int len = sig.length;
0999:                for (;;) {
1000:                    if (i == len)
1001:                        break;
1002:                    char c = sig[i];
1003:                    if (c == ')')
1004:                        break;
1005:                    if (c == '[') {
1006:                        ++i;
1007:                    } else if (c == 'L') {
1008:                        ++count;
1009:                        i = CharOperation.indexOf(';', sig, i + 1) + 1;
1010:                        Assert.isTrue(i != 0);
1011:                    } else {
1012:                        ++count;
1013:                        ++i;
1014:                    }
1015:                }
1016:                return count;
1017:            }
1018:
1019:            /**
1020:             * Put all the arguments in one String.
1021:             */
1022:            public static String getProblemArgumentsForMarker(String[] arguments) {
1023:                StringBuffer args = new StringBuffer(10);
1024:
1025:                args.append(arguments.length);
1026:                args.append(':');
1027:
1028:                for (int j = 0; j < arguments.length; j++) {
1029:                    if (j != 0)
1030:                        args.append(ARGUMENTS_DELIMITER);
1031:
1032:                    if (arguments[j].length() == 0) {
1033:                        args.append(EMPTY_ARGUMENT);
1034:                    } else {
1035:                        args.append(arguments[j]);
1036:                    }
1037:                }
1038:
1039:                return args.toString();
1040:            }
1041:
1042:            /**
1043:             * Separate all the arguments of a String made by getProblemArgumentsForMarker
1044:             */
1045:            public static String[] getProblemArgumentsFromMarker(
1046:                    String argumentsString) {
1047:                if (argumentsString == null)
1048:                    return null;
1049:                int index = argumentsString.indexOf(':');
1050:                if (index == -1)
1051:                    return null;
1052:
1053:                int length = argumentsString.length();
1054:                int numberOfArg;
1055:                try {
1056:                    numberOfArg = Integer.parseInt(argumentsString.substring(0,
1057:                            index));
1058:                } catch (NumberFormatException e) {
1059:                    return null;
1060:                }
1061:                argumentsString = argumentsString.substring(index + 1, length);
1062:
1063:                String[] args = new String[length];
1064:                int count = 0;
1065:
1066:                StringTokenizer tokenizer = new StringTokenizer(
1067:                        argumentsString, ARGUMENTS_DELIMITER);
1068:                while (tokenizer.hasMoreTokens()) {
1069:                    String argument = tokenizer.nextToken();
1070:                    if (argument.equals(EMPTY_ARGUMENT))
1071:                        argument = ""; //$NON-NLS-1$
1072:                    args[count++] = argument;
1073:                }
1074:
1075:                if (count != numberOfArg)
1076:                    return null;
1077:
1078:                System.arraycopy(args, 0, args = new String[count], 0, count);
1079:                return args;
1080:            }
1081:
1082:            /**
1083:             * Returns the given file's contents as a byte array.
1084:             */
1085:            public static byte[] getResourceContentsAsByteArray(IFile file)
1086:                    throws JavaModelException {
1087:                InputStream stream = null;
1088:                try {
1089:                    stream = file.getContents(true);
1090:                } catch (CoreException e) {
1091:                    throw new JavaModelException(e);
1092:                }
1093:                try {
1094:                    return org.eclipse.jdt.internal.compiler.util.Util
1095:                            .getInputStreamAsByteArray(stream, -1);
1096:                } catch (IOException e) {
1097:                    throw new JavaModelException(e,
1098:                            IJavaModelStatusConstants.IO_EXCEPTION);
1099:                } finally {
1100:                    try {
1101:                        stream.close();
1102:                    } catch (IOException e) {
1103:                        // ignore
1104:                    }
1105:                }
1106:            }
1107:
1108:            /**
1109:             * Returns the given file's contents as a character array.
1110:             */
1111:            public static char[] getResourceContentsAsCharArray(IFile file)
1112:                    throws JavaModelException {
1113:                // Get encoding from file
1114:                String encoding;
1115:                try {
1116:                    encoding = file.getCharset();
1117:                } catch (CoreException ce) {
1118:                    // do not use any encoding
1119:                    encoding = null;
1120:                }
1121:                return getResourceContentsAsCharArray(file, encoding);
1122:            }
1123:
1124:            public static char[] getResourceContentsAsCharArray(IFile file,
1125:                    String encoding) throws JavaModelException {
1126:                // Get file length
1127:                // workaround https://bugs.eclipse.org/bugs/show_bug.cgi?id=130736 by using java.io.File if possible
1128:                IPath location = file.getLocation();
1129:                long length;
1130:                if (location == null) {
1131:                    // non local file
1132:                    try {
1133:                        length = EFS.getStore(file.getLocationURI())
1134:                                .fetchInfo().getLength();
1135:                    } catch (CoreException e) {
1136:                        throw new JavaModelException(e);
1137:                    }
1138:                } else {
1139:                    // local file
1140:                    length = location.toFile().length();
1141:                }
1142:
1143:                // Get resource contents
1144:                InputStream stream = null;
1145:                try {
1146:                    stream = file.getContents(true);
1147:                } catch (CoreException e) {
1148:                    throw new JavaModelException(e,
1149:                            IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST);
1150:                }
1151:                try {
1152:                    return org.eclipse.jdt.internal.compiler.util.Util
1153:                            .getInputStreamAsCharArray(stream, (int) length,
1154:                                    encoding);
1155:                } catch (IOException e) {
1156:                    throw new JavaModelException(e,
1157:                            IJavaModelStatusConstants.IO_EXCEPTION);
1158:                } finally {
1159:                    try {
1160:                        stream.close();
1161:                    } catch (IOException e) {
1162:                        // ignore
1163:                    }
1164:                }
1165:            }
1166:
1167:            /*
1168:             * Returns the signature of the given type.
1169:             */
1170:            public static String getSignature(Type type) {
1171:                StringBuffer buffer = new StringBuffer();
1172:                getFullyQualifiedName(type, buffer);
1173:                return Signature
1174:                        .createTypeSignature(buffer.toString(), false/*not resolved in source*/);
1175:            }
1176:
1177:            /*
1178:             * Returns the source attachment property for this package fragment root's path
1179:             */
1180:            public static String getSourceAttachmentProperty(IPath path)
1181:                    throws JavaModelException {
1182:                Map rootPathToAttachments = JavaModelManager
1183:                        .getJavaModelManager().rootPathToAttachments;
1184:                String property = (String) rootPathToAttachments.get(path);
1185:                if (property == null) {
1186:                    try {
1187:                        property = ResourcesPlugin.getWorkspace().getRoot()
1188:                                .getPersistentProperty(
1189:                                        getSourceAttachmentPropertyName(path));
1190:                        if (property == null) {
1191:                            rootPathToAttachments.put(path,
1192:                                    PackageFragmentRoot.NO_SOURCE_ATTACHMENT);
1193:                            return null;
1194:                        }
1195:                        rootPathToAttachments.put(path, property);
1196:                        return property;
1197:                    } catch (CoreException e) {
1198:                        throw new JavaModelException(e);
1199:                    }
1200:                } else if (property
1201:                        .equals(PackageFragmentRoot.NO_SOURCE_ATTACHMENT)) {
1202:                    return null;
1203:                } else
1204:                    return property;
1205:            }
1206:
1207:            private static QualifiedName getSourceAttachmentPropertyName(
1208:                    IPath path) {
1209:                return new QualifiedName(JavaCore.PLUGIN_ID,
1210:                        "sourceattachment: " + path.toOSString()); //$NON-NLS-1$
1211:            }
1212:
1213:            public static void setSourceAttachmentProperty(IPath path,
1214:                    String property) {
1215:                JavaModelManager.getJavaModelManager().rootPathToAttachments
1216:                        .put(path, property);
1217:                try {
1218:                    ResourcesPlugin.getWorkspace().getRoot()
1219:                            .setPersistentProperty(
1220:                                    getSourceAttachmentPropertyName(path),
1221:                                    property);
1222:                } catch (CoreException e) {
1223:                    e.printStackTrace();
1224:                }
1225:            }
1226:
1227:            /*
1228:             * Returns the declaring type signature of the element represented by the given binding key.
1229:             * Returns the signature of the element if it is a type.
1230:             * 
1231:             * @return the declaring type signature
1232:             */
1233:            public static String getDeclaringTypeSignature(String key) {
1234:                KeyToSignature keyToSignature = new KeyToSignature(key,
1235:                        KeyToSignature.DECLARING_TYPE);
1236:                keyToSignature.parse();
1237:                return keyToSignature.signature.toString();
1238:            }
1239:
1240:            /*
1241:             * Appends to the given buffer the fully qualified name (as it appears in the source) of the given type
1242:             */
1243:            private static void getFullyQualifiedName(Type type,
1244:                    StringBuffer buffer) {
1245:                switch (type.getNodeType()) {
1246:                case ASTNode.ARRAY_TYPE:
1247:                    ArrayType arrayType = (ArrayType) type;
1248:                    getFullyQualifiedName(arrayType.getElementType(), buffer);
1249:                    for (int i = 0, length = arrayType.getDimensions(); i < length; i++) {
1250:                        buffer.append('[');
1251:                        buffer.append(']');
1252:                    }
1253:                    break;
1254:                case ASTNode.PARAMETERIZED_TYPE:
1255:                    ParameterizedType parameterizedType = (ParameterizedType) type;
1256:                    getFullyQualifiedName(parameterizedType.getType(), buffer);
1257:                    buffer.append('<');
1258:                    Iterator iterator = parameterizedType.typeArguments()
1259:                            .iterator();
1260:                    boolean isFirst = true;
1261:                    while (iterator.hasNext()) {
1262:                        if (!isFirst)
1263:                            buffer.append(',');
1264:                        else
1265:                            isFirst = false;
1266:                        Type typeArgument = (Type) iterator.next();
1267:                        getFullyQualifiedName(typeArgument, buffer);
1268:                    }
1269:                    buffer.append('>');
1270:                    break;
1271:                case ASTNode.PRIMITIVE_TYPE:
1272:                    buffer.append(((PrimitiveType) type).getPrimitiveTypeCode()
1273:                            .toString());
1274:                    break;
1275:                case ASTNode.QUALIFIED_TYPE:
1276:                    buffer.append(((QualifiedType) type).getName()
1277:                            .getFullyQualifiedName());
1278:                    break;
1279:                case ASTNode.SIMPLE_TYPE:
1280:                    buffer.append(((SimpleType) type).getName()
1281:                            .getFullyQualifiedName());
1282:                    break;
1283:                case ASTNode.WILDCARD_TYPE:
1284:                    buffer.append('?');
1285:                    WildcardType wildcardType = (WildcardType) type;
1286:                    Type bound = wildcardType.getBound();
1287:                    if (bound == null)
1288:                        return;
1289:                    if (wildcardType.isUpperBound()) {
1290:                        buffer.append(" extends "); //$NON-NLS-1$
1291:                    } else {
1292:                        buffer.append(" super "); //$NON-NLS-1$
1293:                    }
1294:                    getFullyQualifiedName(bound, buffer);
1295:                    break;
1296:                }
1297:            }
1298:
1299:            /**
1300:             * Returns a trimmed version the simples names returned by Signature.
1301:             */
1302:            public static String[] getTrimmedSimpleNames(String name) {
1303:                String[] result = Signature.getSimpleNames(name);
1304:                for (int i = 0, length = result.length; i < length; i++) {
1305:                    result[i] = result[i].trim();
1306:                }
1307:                return result;
1308:            }
1309:
1310:            /*
1311:             * Returns the index of the most specific argument paths which is strictly enclosing the path to check
1312:             */
1313:            public static int indexOfEnclosingPath(IPath checkedPath,
1314:                    IPath[] paths, int pathCount) {
1315:
1316:                int bestMatch = -1, bestLength = -1;
1317:                for (int i = 0; i < pathCount; i++) {
1318:                    if (paths[i].equals(checkedPath))
1319:                        continue;
1320:                    if (paths[i].isPrefixOf(checkedPath)) {
1321:                        int currentLength = paths[i].segmentCount();
1322:                        if (currentLength > bestLength) {
1323:                            bestLength = currentLength;
1324:                            bestMatch = i;
1325:                        }
1326:                    }
1327:                }
1328:                return bestMatch;
1329:            }
1330:
1331:            /*
1332:             * Returns the index of the Java like extension of the given file name
1333:             * or -1 if it doesn't end with a known Java like extension. 
1334:             * Note this is the index of the '.' even if it is not considered part of the extension.
1335:             */
1336:            public static int indexOfJavaLikeExtension(String fileName) {
1337:                int fileNameLength = fileName.length();
1338:                char[][] javaLikeExtensions = getJavaLikeExtensions();
1339:                extensions: for (int i = 0, length = javaLikeExtensions.length; i < length; i++) {
1340:                    char[] extension = javaLikeExtensions[i];
1341:                    int extensionLength = extension.length;
1342:                    int extensionStart = fileNameLength - extensionLength;
1343:                    int dotIndex = extensionStart - 1;
1344:                    if (dotIndex < 0)
1345:                        continue;
1346:                    if (fileName.charAt(dotIndex) != '.')
1347:                        continue;
1348:                    for (int j = 0; j < extensionLength; j++) {
1349:                        if (fileName.charAt(extensionStart + j) != extension[j])
1350:                            continue extensions;
1351:                    }
1352:                    return dotIndex;
1353:                }
1354:                return -1;
1355:            }
1356:
1357:            /*
1358:             * Returns the index of the first argument paths which is equal to the path to check
1359:             */
1360:            public static int indexOfMatchingPath(IPath checkedPath,
1361:                    IPath[] paths, int pathCount) {
1362:
1363:                for (int i = 0; i < pathCount; i++) {
1364:                    if (paths[i].equals(checkedPath))
1365:                        return i;
1366:                }
1367:                return -1;
1368:            }
1369:
1370:            /*
1371:             * Returns the index of the first argument paths which is strictly nested inside the path to check
1372:             */
1373:            public static int indexOfNestedPath(IPath checkedPath,
1374:                    IPath[] paths, int pathCount) {
1375:
1376:                for (int i = 0; i < pathCount; i++) {
1377:                    if (checkedPath.equals(paths[i]))
1378:                        continue;
1379:                    if (checkedPath.isPrefixOf(paths[i]))
1380:                        return i;
1381:                }
1382:                return -1;
1383:            }
1384:
1385:            /**
1386:             * Returns whether the local file system supports accessing and modifying
1387:             * the given attribute.
1388:             */
1389:            protected static boolean isAttributeSupported(int attribute) {
1390:                return (EFS.getLocalFileSystem().attributes() & attribute) != 0;
1391:            }
1392:
1393:            /**
1394:             * Returns whether the given resource is read-only or not.
1395:             * @param resource
1396:             * @return <code>true</code> if the resource is read-only, <code>false</code> if it is not or
1397:             * 	if the file system does not support the read-only attribute.
1398:             */
1399:            public static boolean isReadOnly(IResource resource) {
1400:                if (isReadOnlySupported()) {
1401:                    ResourceAttributes resourceAttributes = resource
1402:                            .getResourceAttributes();
1403:                    if (resourceAttributes == null)
1404:                        return false; // not supported on this platform for this resource
1405:                    return resourceAttributes.isReadOnly();
1406:                }
1407:                return false;
1408:            }
1409:
1410:            /**
1411:             * Returns whether the local file system supports accessing and modifying
1412:             * the read only flag.
1413:             */
1414:            public static boolean isReadOnlySupported() {
1415:                return isAttributeSupported(EFS.ATTRIBUTE_READ_ONLY);
1416:            }
1417:
1418:            /*
1419:             * Returns whether the given java element is exluded from its root's classpath.
1420:             * It doesn't check whether the root itself is on the classpath or not
1421:             */
1422:            public static final boolean isExcluded(IJavaElement element) {
1423:                int elementType = element.getElementType();
1424:                switch (elementType) {
1425:                case IJavaElement.JAVA_MODEL:
1426:                case IJavaElement.JAVA_PROJECT:
1427:                case IJavaElement.PACKAGE_FRAGMENT_ROOT:
1428:                    return false;
1429:
1430:                case IJavaElement.PACKAGE_FRAGMENT:
1431:                    PackageFragmentRoot root = (PackageFragmentRoot) element
1432:                            .getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
1433:                    IResource resource = element.getResource();
1434:                    return resource != null
1435:                            && isExcluded(resource, root
1436:                                    .fullInclusionPatternChars(), root
1437:                                    .fullExclusionPatternChars());
1438:
1439:                case IJavaElement.COMPILATION_UNIT:
1440:                    root = (PackageFragmentRoot) element
1441:                            .getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
1442:                    resource = element.getResource();
1443:                    if (resource == null)
1444:                        return false;
1445:                    if (isExcluded(resource, root.fullInclusionPatternChars(),
1446:                            root.fullExclusionPatternChars()))
1447:                        return true;
1448:                    return isExcluded(element.getParent());
1449:
1450:                default:
1451:                    IJavaElement cu = element
1452:                            .getAncestor(IJavaElement.COMPILATION_UNIT);
1453:                    return cu != null && isExcluded(cu);
1454:                }
1455:            }
1456:
1457:            /*
1458:             * Returns whether the given resource path matches one of the inclusion/exclusion
1459:             * patterns.
1460:             * NOTE: should not be asked directly using pkg root pathes
1461:             * @see IClasspathEntry#getInclusionPatterns
1462:             * @see IClasspathEntry#getExclusionPatterns
1463:             */
1464:            public final static boolean isExcluded(IPath resourcePath,
1465:                    char[][] inclusionPatterns, char[][] exclusionPatterns,
1466:                    boolean isFolderPath) {
1467:                if (inclusionPatterns == null && exclusionPatterns == null)
1468:                    return false;
1469:                return org.eclipse.jdt.internal.compiler.util.Util.isExcluded(
1470:                        resourcePath.toString().toCharArray(),
1471:                        inclusionPatterns, exclusionPatterns, isFolderPath);
1472:            }
1473:
1474:            /*
1475:             * Returns whether the given resource matches one of the exclusion patterns.
1476:             * NOTE: should not be asked directly using pkg root pathes
1477:             * @see IClasspathEntry#getExclusionPatterns
1478:             */
1479:            public final static boolean isExcluded(IResource resource,
1480:                    char[][] inclusionPatterns, char[][] exclusionPatterns) {
1481:                IPath path = resource.getFullPath();
1482:                // ensure that folders are only excluded if all of their children are excluded
1483:                int resourceType = resource.getType();
1484:                return isExcluded(path, inclusionPatterns, exclusionPatterns,
1485:                        resourceType == IResource.FOLDER
1486:                                || resourceType == IResource.PROJECT);
1487:            }
1488:
1489:            /**
1490:             * Validate the given .class file name.
1491:             * A .class file name must obey the following rules:
1492:             * <ul>
1493:             * <li> it must not be null
1494:             * <li> it must include the <code>".class"</code> suffix
1495:             * <li> its prefix must be a valid identifier
1496:             * </ul>
1497:             * </p>
1498:             * @param name the name of a .class file
1499:             * @param sourceLevel the source level
1500:             * @param complianceLevel the compliance level
1501:             * @return a status object with code <code>IStatus.OK</code> if
1502:             *		the given name is valid as a .class file name, otherwise a status 
1503:             *		object indicating what is wrong with the name
1504:             */
1505:            public static boolean isValidClassFileName(String name,
1506:                    String sourceLevel, String complianceLevel) {
1507:                return JavaConventions.validateClassFileName(name, sourceLevel,
1508:                        complianceLevel).getSeverity() != IStatus.ERROR;
1509:            }
1510:
1511:            /**
1512:             * Validate the given compilation unit name.
1513:             * A compilation unit name must obey the following rules:
1514:             * <ul>
1515:             * <li> it must not be null
1516:             * <li> it must include the <code>".java"</code> suffix
1517:             * <li> its prefix must be a valid identifier
1518:             * </ul>
1519:             * </p>
1520:             * @param name the name of a compilation unit
1521:             * @param sourceLevel the source level
1522:             * @param complianceLevel the compliance level
1523:             * @return a status object with code <code>IStatus.OK</code> if
1524:             *		the given name is valid as a compilation unit name, otherwise a status 
1525:             *		object indicating what is wrong with the name
1526:             */
1527:            public static boolean isValidCompilationUnitName(String name,
1528:                    String sourceLevel, String complianceLevel) {
1529:                return JavaConventions.validateCompilationUnitName(name,
1530:                        sourceLevel, complianceLevel).getSeverity() != IStatus.ERROR;
1531:            }
1532:
1533:            /**
1534:             * Returns true if the given folder name is valid for a package,
1535:             * false if it is not.
1536:             * @param folderName the name of the folder
1537:             * @param sourceLevel the source level
1538:             * @param complianceLevel the compliance level
1539:             */
1540:            public static boolean isValidFolderNameForPackage(
1541:                    String folderName, String sourceLevel,
1542:                    String complianceLevel) {
1543:                return JavaConventions.validateIdentifier(folderName,
1544:                        sourceLevel, complianceLevel).getSeverity() != IStatus.ERROR;
1545:            }
1546:
1547:            /**
1548:             * Returns true if the given method signature is valid,
1549:             * false if it is not.
1550:             */
1551:            public static boolean isValidMethodSignature(String sig) {
1552:                int len = sig.length();
1553:                if (len == 0)
1554:                    return false;
1555:                int i = 0;
1556:                char c = sig.charAt(i++);
1557:                if (c != '(')
1558:                    return false;
1559:                if (i >= len)
1560:                    return false;
1561:                while (sig.charAt(i) != ')') {
1562:                    // Void is not allowed as a parameter type.
1563:                    i = checkTypeSignature(sig, i, len, false);
1564:                    if (i == -1)
1565:                        return false;
1566:                    if (i >= len)
1567:                        return false;
1568:                }
1569:                ++i;
1570:                i = checkTypeSignature(sig, i, len, true);
1571:                return i == len;
1572:            }
1573:
1574:            /**
1575:             * Returns true if the given type signature is valid,
1576:             * false if it is not.
1577:             */
1578:            public static boolean isValidTypeSignature(String sig,
1579:                    boolean allowVoid) {
1580:                int len = sig.length();
1581:                return checkTypeSignature(sig, 0, len, allowVoid) == len;
1582:            }
1583:
1584:            /*
1585:             * Returns the simple name of a local type from the given binary type name.
1586:             * The last '$' is at lastDollar. The last character of the type name is at end-1.
1587:             */
1588:            public static String localTypeName(String binaryTypeName,
1589:                    int lastDollar, int end) {
1590:                if (lastDollar > 0
1591:                        && binaryTypeName.charAt(lastDollar - 1) == '$')
1592:                    // local name starts with a dollar sign
1593:                    // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=103466)
1594:                    return binaryTypeName;
1595:                int nameStart = lastDollar + 1;
1596:                while (nameStart < end
1597:                        && Character.isDigit(binaryTypeName.charAt(nameStart)))
1598:                    nameStart++;
1599:                return binaryTypeName.substring(nameStart, end);
1600:            }
1601:
1602:            /*
1603:             * Add a log entry
1604:             */
1605:            public static void log(Throwable e, String message) {
1606:                Throwable nestedException;
1607:                if (e instanceof  JavaModelException
1608:                        && (nestedException = ((JavaModelException) e)
1609:                                .getException()) != null) {
1610:                    e = nestedException;
1611:                }
1612:                IStatus status = new Status(IStatus.ERROR, JavaCore.PLUGIN_ID,
1613:                        IStatus.ERROR, message, e);
1614:                JavaCore.getPlugin().getLog().log(status);
1615:            }
1616:
1617:            public static ClassFileReader newClassFileReader(IResource resource)
1618:                    throws CoreException, ClassFormatException, IOException {
1619:                InputStream in = null;
1620:                try {
1621:                    in = ((IFile) resource).getContents(true);
1622:                    return ClassFileReader.read(in, resource.getFullPath()
1623:                            .toString());
1624:                } finally {
1625:                    if (in != null)
1626:                        in.close();
1627:                }
1628:            }
1629:
1630:            /**
1631:             * Normalizes the cariage returns in the given text.
1632:             * They are all changed  to use the given buffer's line separator.
1633:             */
1634:            public static char[] normalizeCRs(char[] text, char[] buffer) {
1635:                CharArrayBuffer result = new CharArrayBuffer();
1636:                int lineStart = 0;
1637:                int length = text.length;
1638:                if (length == 0)
1639:                    return text;
1640:                String lineSeparator = getLineSeparator(text, buffer);
1641:                char nextChar = text[0];
1642:                for (int i = 0; i < length; i++) {
1643:                    char currentChar = nextChar;
1644:                    nextChar = i < length - 1 ? text[i + 1] : ' ';
1645:                    switch (currentChar) {
1646:                    case '\n':
1647:                        int lineLength = i - lineStart;
1648:                        char[] line = new char[lineLength];
1649:                        System.arraycopy(text, lineStart, line, 0, lineLength);
1650:                        result.append(line);
1651:                        result.append(lineSeparator);
1652:                        lineStart = i + 1;
1653:                        break;
1654:                    case '\r':
1655:                        lineLength = i - lineStart;
1656:                        if (lineLength >= 0) {
1657:                            line = new char[lineLength];
1658:                            System.arraycopy(text, lineStart, line, 0,
1659:                                    lineLength);
1660:                            result.append(line);
1661:                            result.append(lineSeparator);
1662:                            if (nextChar == '\n') {
1663:                                nextChar = ' ';
1664:                                lineStart = i + 2;
1665:                            } else {
1666:                                // when line separator are mixed in the same file
1667:                                // \r might not be followed by a \n. If not, we should increment
1668:                                // lineStart by one and not by two.
1669:                                lineStart = i + 1;
1670:                            }
1671:                        } else {
1672:                            // when line separator are mixed in the same file
1673:                            // we need to prevent NegativeArraySizeException
1674:                            lineStart = i + 1;
1675:                        }
1676:                        break;
1677:                    }
1678:                }
1679:                char[] lastLine;
1680:                if (lineStart > 0) {
1681:                    int lastLineLength = length - lineStart;
1682:                    if (lastLineLength > 0) {
1683:                        lastLine = new char[lastLineLength];
1684:                        System.arraycopy(text, lineStart, lastLine, 0,
1685:                                lastLineLength);
1686:                        result.append(lastLine);
1687:                    }
1688:                    return result.getContents();
1689:                }
1690:                return text;
1691:            }
1692:
1693:            /**
1694:             * Normalizes the cariage returns in the given text.
1695:             * They are all changed  to use given buffer's line sepatator.
1696:             */
1697:            public static String normalizeCRs(String text, String buffer) {
1698:                return new String(normalizeCRs(text.toCharArray(), buffer
1699:                        .toCharArray()));
1700:            }
1701:
1702:            /**
1703:             * Converts the given relative path into a package name.
1704:             * Returns null if the path is not a valid package name.
1705:             * @param pkgPath the package path
1706:             * @param sourceLevel the source level
1707:             * @param complianceLevel the compliance level
1708:             */
1709:            public static String packageName(IPath pkgPath, String sourceLevel,
1710:                    String complianceLevel) {
1711:                StringBuffer pkgName = new StringBuffer(
1712:                        IPackageFragment.DEFAULT_PACKAGE_NAME);
1713:                for (int j = 0, max = pkgPath.segmentCount(); j < max; j++) {
1714:                    String segment = pkgPath.segment(j);
1715:                    if (!isValidFolderNameForPackage(segment, sourceLevel,
1716:                            complianceLevel)) {
1717:                        return null;
1718:                    }
1719:                    pkgName.append(segment);
1720:                    if (j < pkgPath.segmentCount() - 1) {
1721:                        pkgName.append("."); //$NON-NLS-1$
1722:                    }
1723:                }
1724:                return pkgName.toString();
1725:            }
1726:
1727:            /**
1728:             * Returns the length of the common prefix between s1 and s2.
1729:             */
1730:            public static int prefixLength(char[] s1, char[] s2) {
1731:                int len = 0;
1732:                int max = Math.min(s1.length, s2.length);
1733:                for (int i = 0; i < max && s1[i] == s2[i]; ++i)
1734:                    ++len;
1735:                return len;
1736:            }
1737:
1738:            /**
1739:             * Returns the length of the common prefix between s1 and s2.
1740:             */
1741:            public static int prefixLength(String s1, String s2) {
1742:                int len = 0;
1743:                int max = Math.min(s1.length(), s2.length());
1744:                for (int i = 0; i < max && s1.charAt(i) == s2.charAt(i); ++i)
1745:                    ++len;
1746:                return len;
1747:            }
1748:
1749:            private static void quickSort(char[][] list, int left, int right) {
1750:                int original_left = left;
1751:                int original_right = right;
1752:                char[] mid = list[left + (right - left) / 2];
1753:                do {
1754:                    while (compare(list[left], mid) < 0) {
1755:                        left++;
1756:                    }
1757:                    while (compare(mid, list[right]) < 0) {
1758:                        right--;
1759:                    }
1760:                    if (left <= right) {
1761:                        char[] tmp = list[left];
1762:                        list[left] = list[right];
1763:                        list[right] = tmp;
1764:                        left++;
1765:                        right--;
1766:                    }
1767:                } while (left <= right);
1768:                if (original_left < right) {
1769:                    quickSort(list, original_left, right);
1770:                }
1771:                if (left < original_right) {
1772:                    quickSort(list, left, original_right);
1773:                }
1774:            }
1775:
1776:            /**
1777:             * Sort the comparable objects in the given collection.
1778:             */
1779:            private static void quickSort(Comparable[] sortedCollection,
1780:                    int left, int right) {
1781:                int original_left = left;
1782:                int original_right = right;
1783:                Comparable mid = sortedCollection[left + (right - left) / 2];
1784:                do {
1785:                    while (sortedCollection[left].compareTo(mid) < 0) {
1786:                        left++;
1787:                    }
1788:                    while (mid.compareTo(sortedCollection[right]) < 0) {
1789:                        right--;
1790:                    }
1791:                    if (left <= right) {
1792:                        Comparable tmp = sortedCollection[left];
1793:                        sortedCollection[left] = sortedCollection[right];
1794:                        sortedCollection[right] = tmp;
1795:                        left++;
1796:                        right--;
1797:                    }
1798:                } while (left <= right);
1799:                if (original_left < right) {
1800:                    quickSort(sortedCollection, original_left, right);
1801:                }
1802:                if (left < original_right) {
1803:                    quickSort(sortedCollection, left, original_right);
1804:                }
1805:            }
1806:
1807:            private static void quickSort(int[] list, int left, int right) {
1808:                int original_left = left;
1809:                int original_right = right;
1810:                int mid = list[left + (right - left) / 2];
1811:                do {
1812:                    while (list[left] < mid) {
1813:                        left++;
1814:                    }
1815:                    while (mid < list[right]) {
1816:                        right--;
1817:                    }
1818:                    if (left <= right) {
1819:                        int tmp = list[left];
1820:                        list[left] = list[right];
1821:                        list[right] = tmp;
1822:                        left++;
1823:                        right--;
1824:                    }
1825:                } while (left <= right);
1826:                if (original_left < right) {
1827:                    quickSort(list, original_left, right);
1828:                }
1829:                if (left < original_right) {
1830:                    quickSort(list, left, original_right);
1831:                }
1832:            }
1833:
1834:            /**
1835:             * Sort the objects in the given collection using the given comparer.
1836:             */
1837:            private static void quickSort(Object[] sortedCollection, int left,
1838:                    int right, Comparer comparer) {
1839:                int original_left = left;
1840:                int original_right = right;
1841:                Object mid = sortedCollection[left + (right - left) / 2];
1842:                do {
1843:                    while (comparer.compare(sortedCollection[left], mid) < 0) {
1844:                        left++;
1845:                    }
1846:                    while (comparer.compare(mid, sortedCollection[right]) < 0) {
1847:                        right--;
1848:                    }
1849:                    if (left <= right) {
1850:                        Object tmp = sortedCollection[left];
1851:                        sortedCollection[left] = sortedCollection[right];
1852:                        sortedCollection[right] = tmp;
1853:                        left++;
1854:                        right--;
1855:                    }
1856:                } while (left <= right);
1857:                if (original_left < right) {
1858:                    quickSort(sortedCollection, original_left, right, comparer);
1859:                }
1860:                if (left < original_right) {
1861:                    quickSort(sortedCollection, left, original_right, comparer);
1862:                }
1863:            }
1864:
1865:            /**
1866:             * Sort the strings in the given collection.
1867:             */
1868:            private static void quickSort(String[] sortedCollection, int left,
1869:                    int right) {
1870:                int original_left = left;
1871:                int original_right = right;
1872:                String mid = sortedCollection[left + (right - left) / 2];
1873:                do {
1874:                    while (sortedCollection[left].compareTo(mid) < 0) {
1875:                        left++;
1876:                    }
1877:                    while (mid.compareTo(sortedCollection[right]) < 0) {
1878:                        right--;
1879:                    }
1880:                    if (left <= right) {
1881:                        String tmp = sortedCollection[left];
1882:                        sortedCollection[left] = sortedCollection[right];
1883:                        sortedCollection[right] = tmp;
1884:                        left++;
1885:                        right--;
1886:                    }
1887:                } while (left <= right);
1888:                if (original_left < right) {
1889:                    quickSort(sortedCollection, original_left, right);
1890:                }
1891:                if (left < original_right) {
1892:                    quickSort(sortedCollection, left, original_right);
1893:                }
1894:            }
1895:
1896:            /**
1897:             * Returns the toString() of the given full path minus the first given number of segments.
1898:             * The returned string is always a relative path (it has no leading slash)
1899:             */
1900:            public static String relativePath(IPath fullPath,
1901:                    int skipSegmentCount) {
1902:                boolean hasTrailingSeparator = fullPath.hasTrailingSeparator();
1903:                String[] segments = fullPath.segments();
1904:
1905:                // compute length
1906:                int length = 0;
1907:                int max = segments.length;
1908:                if (max > skipSegmentCount) {
1909:                    for (int i1 = skipSegmentCount; i1 < max; i1++) {
1910:                        length += segments[i1].length();
1911:                    }
1912:                    //add the separator lengths
1913:                    length += max - skipSegmentCount - 1;
1914:                }
1915:                if (hasTrailingSeparator)
1916:                    length++;
1917:
1918:                char[] result = new char[length];
1919:                int offset = 0;
1920:                int len = segments.length - 1;
1921:                if (len >= skipSegmentCount) {
1922:                    //append all but the last segment, with separators
1923:                    for (int i = skipSegmentCount; i < len; i++) {
1924:                        int size = segments[i].length();
1925:                        segments[i].getChars(0, size, result, offset);
1926:                        offset += size;
1927:                        result[offset++] = '/';
1928:                    }
1929:                    //append the last segment
1930:                    int size = segments[len].length();
1931:                    segments[len].getChars(0, size, result, offset);
1932:                    offset += size;
1933:                }
1934:                if (hasTrailingSeparator)
1935:                    result[offset++] = '/';
1936:                return new String(result);
1937:            }
1938:
1939:            /*
1940:             * Resets the list of Java-like extensions after a change in content-type.
1941:             */
1942:            public static void resetJavaLikeExtensions() {
1943:                JAVA_LIKE_EXTENSIONS = null;
1944:            }
1945:
1946:            /**
1947:             * Return a new array which is the split of the given string using the given divider. The given end 
1948:             * is exclusive and the given start is inclusive.
1949:             * <br>
1950:             * <br>
1951:             * For example:
1952:             * <ol>
1953:             * <li><pre>
1954:             *    divider = 'b'
1955:             *    string = "abbaba"
1956:             *    start = 2
1957:             *    end = 5
1958:             *    result => { "", "a", "" }
1959:             * </pre>
1960:             * </li>
1961:             * </ol>
1962:             * 
1963:             * @param divider the given divider
1964:             * @param string the given string
1965:             * @param start the given starting index
1966:             * @param end the given ending index
1967:             * @return a new array which is the split of the given string using the given divider
1968:             * @throws ArrayIndexOutOfBoundsException if start is lower than 0 or end is greater than the array length
1969:             */
1970:            public static final String[] splitOn(char divider, String string,
1971:                    int start, int end) {
1972:                int length = string == null ? 0 : string.length();
1973:                if (length == 0 || start > end)
1974:                    return CharOperation.NO_STRINGS;
1975:
1976:                int wordCount = 1;
1977:                for (int i = start; i < end; i++)
1978:                    if (string.charAt(i) == divider)
1979:                        wordCount++;
1980:                String[] split = new String[wordCount];
1981:                int last = start, currentWord = 0;
1982:                for (int i = start; i < end; i++) {
1983:                    if (string.charAt(i) == divider) {
1984:                        split[currentWord++] = string.substring(last, i);
1985:                        last = i + 1;
1986:                    }
1987:                }
1988:                split[currentWord] = string.substring(last, end);
1989:                return split;
1990:            }
1991:
1992:            /**
1993:             * Sets or unsets the given resource as read-only in the file system.
1994:             * It's a no-op if the file system does not support the read-only attribute.
1995:             * 
1996:             * @param resource The resource to set as read-only
1997:             * @param readOnly <code>true</code> to set it to read-only, 
1998:             *		<code>false</code> to unset
1999:             */
2000:            public static void setReadOnly(IResource resource, boolean readOnly) {
2001:                if (isReadOnlySupported()) {
2002:                    ResourceAttributes resourceAttributes = resource
2003:                            .getResourceAttributes();
2004:                    if (resourceAttributes == null)
2005:                        return; // not supported on this platform for this resource
2006:                    resourceAttributes.setReadOnly(readOnly);
2007:                    try {
2008:                        resource.setResourceAttributes(resourceAttributes);
2009:                    } catch (CoreException e) {
2010:                        // ignore
2011:                    }
2012:                }
2013:            }
2014:
2015:            public static void sort(char[][] list) {
2016:                if (list.length > 1)
2017:                    quickSort(list, 0, list.length - 1);
2018:            }
2019:
2020:            /**
2021:             * Sorts an array of Comparable objects in place.
2022:             */
2023:            public static void sort(Comparable[] objects) {
2024:                if (objects.length > 1)
2025:                    quickSort(objects, 0, objects.length - 1);
2026:            }
2027:
2028:            public static void sort(int[] list) {
2029:                if (list.length > 1)
2030:                    quickSort(list, 0, list.length - 1);
2031:            }
2032:
2033:            /**
2034:             * Sorts an array of objects in place.
2035:             * The given comparer compares pairs of items.
2036:             */
2037:            public static void sort(Object[] objects, Comparer comparer) {
2038:                if (objects.length > 1)
2039:                    quickSort(objects, 0, objects.length - 1, comparer);
2040:            }
2041:
2042:            /**
2043:             * Sorts an array of strings in place using quicksort.
2044:             */
2045:            public static void sort(String[] strings) {
2046:                if (strings.length > 1)
2047:                    quickSort(strings, 0, strings.length - 1);
2048:            }
2049:
2050:            /**
2051:             * Sorts an array of Comparable objects, returning a new array
2052:             * with the sorted items.  The original array is left untouched.
2053:             */
2054:            public static Comparable[] sortCopy(Comparable[] objects) {
2055:                int len = objects.length;
2056:                Comparable[] copy = new Comparable[len];
2057:                System.arraycopy(objects, 0, copy, 0, len);
2058:                sort(copy);
2059:                return copy;
2060:            }
2061:
2062:            /**
2063:             * Sorts an array of Java elements based on their toStringWithAncestors(), 
2064:             * returning a new array with the sorted items. 
2065:             * The original array is left untouched.
2066:             */
2067:            public static IJavaElement[] sortCopy(IJavaElement[] elements) {
2068:                int len = elements.length;
2069:                IJavaElement[] copy = new IJavaElement[len];
2070:                System.arraycopy(elements, 0, copy, 0, len);
2071:                sort(copy, new Comparer() {
2072:                    public int compare(Object a, Object b) {
2073:                        return ((JavaElement) a).toStringWithAncestors()
2074:                                .compareTo(
2075:                                        ((JavaElement) b)
2076:                                                .toStringWithAncestors());
2077:                    }
2078:                });
2079:                return copy;
2080:            }
2081:
2082:            /**
2083:             * Sorts an array of Strings, returning a new array
2084:             * with the sorted items.  The original array is left untouched.
2085:             */
2086:            public static Object[] sortCopy(Object[] objects, Comparer comparer) {
2087:                int len = objects.length;
2088:                Object[] copy = new Object[len];
2089:                System.arraycopy(objects, 0, copy, 0, len);
2090:                sort(copy, comparer);
2091:                return copy;
2092:            }
2093:
2094:            /**
2095:             * Sorts an array of Strings, returning a new array
2096:             * with the sorted items.  The original array is left untouched.
2097:             */
2098:            public static String[] sortCopy(String[] objects) {
2099:                int len = objects.length;
2100:                String[] copy = new String[len];
2101:                System.arraycopy(objects, 0, copy, 0, len);
2102:                sort(copy);
2103:                return copy;
2104:            }
2105:
2106:            /*
2107:             * Returns whether the given compound name starts with the given prefix.
2108:             * Returns true if the n first elements of the prefix are equals and the last element of the 
2109:             * prefix is a prefix of the corresponding element in the compound name.
2110:             */
2111:            public static boolean startsWithIgnoreCase(String[] compoundName,
2112:                    String[] prefix, boolean partialMatch) {
2113:                int prefixLength = prefix.length;
2114:                int nameLength = compoundName.length;
2115:                if (prefixLength > nameLength)
2116:                    return false;
2117:                for (int i = 0; i < prefixLength - 1; i++) {
2118:                    if (!compoundName[i].equalsIgnoreCase(prefix[i]))
2119:                        return false;
2120:                }
2121:                return (partialMatch || prefixLength == nameLength)
2122:                        && compoundName[prefixLength - 1].toLowerCase()
2123:                                .startsWith(
2124:                                        prefix[prefixLength - 1].toLowerCase());
2125:            }
2126:
2127:            /*
2128:             * Returns whether the given compound name matches the given pattern.
2129:             */
2130:            public static boolean matchesWithIgnoreCase(String[] compoundName,
2131:                    String pattern) {
2132:                if (pattern.equals("*"))return true; //$NON-NLS-1$
2133:                int nameLength = compoundName.length;
2134:                if (pattern.length() == 0)
2135:                    return nameLength == 0;
2136:                if (nameLength == 0)
2137:                    return false;
2138:                int length = nameLength - 1;
2139:                for (int i = 0; i < nameLength; i++) {
2140:                    length += compoundName[i].length();
2141:                }
2142:                char[] compoundChars = new char[length];
2143:                int pos = 0;
2144:                for (int i = 0; i < nameLength; i++) {
2145:                    if (pos > 0)
2146:                        compoundChars[pos++] = '.';
2147:                    char[] array = compoundName[i].toCharArray();
2148:                    int size = array.length;
2149:                    System.arraycopy(array, 0, compoundChars, pos, size);
2150:                    pos += size;
2151:                }
2152:                return CharOperation.match(pattern.toCharArray(),
2153:                        compoundChars, false);
2154:            }
2155:
2156:            /**
2157:             * Converts a String[] to char[][].
2158:             */
2159:            public static char[][] toCharArrays(String[] a) {
2160:                int len = a.length;
2161:                if (len == 0)
2162:                    return CharOperation.NO_CHAR_CHAR;
2163:                char[][] result = new char[len][];
2164:                for (int i = 0; i < len; ++i) {
2165:                    result[i] = a[i].toCharArray();
2166:                }
2167:                return result;
2168:            }
2169:
2170:            /**
2171:             * Converts a String to char[][], where segments are separate by '.'.
2172:             */
2173:            public static char[][] toCompoundChars(String s) {
2174:                int len = s.length();
2175:                if (len == 0) {
2176:                    return CharOperation.NO_CHAR_CHAR;
2177:                }
2178:                int segCount = 1;
2179:                for (int off = s.indexOf('.'); off != -1; off = s.indexOf('.',
2180:                        off + 1)) {
2181:                    ++segCount;
2182:                }
2183:                char[][] segs = new char[segCount][];
2184:                int start = 0;
2185:                for (int i = 0; i < segCount; ++i) {
2186:                    int dot = s.indexOf('.', start);
2187:                    int end = (dot == -1 ? s.length() : dot);
2188:                    segs[i] = new char[end - start];
2189:                    s.getChars(start, end, segs[i], 0);
2190:                    start = end + 1;
2191:                }
2192:                return segs;
2193:            }
2194:
2195:            /*
2196:             * Converts the given URI to a local file. Use the existing file if the uri is on the local file system.
2197:             * Otherwise fetch it.
2198:             * Returns null if unable to fetch it.
2199:             */
2200:            public static File toLocalFile(URI uri, IProgressMonitor monitor)
2201:                    throws CoreException {
2202:                IFileStore fileStore = EFS.getStore(uri);
2203:                File localFile = fileStore.toLocalFile(EFS.NONE, monitor);
2204:                if (localFile == null)
2205:                    // non local file system
2206:                    localFile = fileStore.toLocalFile(EFS.CACHE, monitor);
2207:                return localFile;
2208:            }
2209:
2210:            /**
2211:             * Converts a char[][] to String, where segments are separated by '.'.
2212:             */
2213:            public static String toString(char[][] c) {
2214:                StringBuffer sb = new StringBuffer();
2215:                for (int i = 0, max = c.length; i < max; ++i) {
2216:                    if (i != 0)
2217:                        sb.append('.');
2218:                    sb.append(c[i]);
2219:                }
2220:                return sb.toString();
2221:            }
2222:
2223:            /**
2224:             * Converts a char[][] and a char[] to String, where segments are separated by '.'.
2225:             */
2226:            public static String toString(char[][] c, char[] d) {
2227:                if (c == null)
2228:                    return new String(d);
2229:                StringBuffer sb = new StringBuffer();
2230:                for (int i = 0, max = c.length; i < max; ++i) {
2231:                    sb.append(c[i]);
2232:                    sb.append('.');
2233:                }
2234:                sb.append(d);
2235:                return sb.toString();
2236:            }
2237:
2238:            /*
2239:             * Converts a char[][] to String[].
2240:             */
2241:            public static String[] toStrings(char[][] a) {
2242:                int len = a.length;
2243:                String[] result = new String[len];
2244:                for (int i = 0; i < len; ++i) {
2245:                    result[i] = new String(a[i]);
2246:                }
2247:                return result;
2248:            }
2249:
2250:            private static void appendArrayTypeSignature(char[] string,
2251:                    int start, StringBuffer buffer, boolean compact) {
2252:                int length = string.length;
2253:                // need a minimum 2 char
2254:                if (start >= length - 1) {
2255:                    throw new IllegalArgumentException();
2256:                }
2257:                char c = string[start];
2258:                if (c != Signature.C_ARRAY) {
2259:                    throw new IllegalArgumentException();
2260:                }
2261:
2262:                int index = start;
2263:                c = string[++index];
2264:                while (c == Signature.C_ARRAY) {
2265:                    // need a minimum 2 char
2266:                    if (index >= length - 1) {
2267:                        throw new IllegalArgumentException();
2268:                    }
2269:                    c = string[++index];
2270:                }
2271:
2272:                appendTypeSignature(string, index, buffer, compact);
2273:
2274:                for (int i = 0, dims = index - start; i < dims; i++) {
2275:                    buffer.append('[').append(']');
2276:                }
2277:            }
2278:
2279:            private static void appendClassTypeSignature(char[] string,
2280:                    int start, StringBuffer buffer, boolean compact) {
2281:                char c = string[start];
2282:                if (c != Signature.C_RESOLVED) {
2283:                    return;
2284:                }
2285:                int p = start + 1;
2286:                int checkpoint = buffer.length();
2287:                while (true) {
2288:                    c = string[p];
2289:                    switch (c) {
2290:                    case Signature.C_SEMICOLON:
2291:                        // all done
2292:                        return;
2293:                    case Signature.C_DOT:
2294:                    case '/':
2295:                        // erase package prefix
2296:                        if (compact) {
2297:                            buffer.setLength(checkpoint);
2298:                        } else {
2299:                            buffer.append('.');
2300:                        }
2301:                        break;
2302:                    case Signature.C_DOLLAR:
2303:                        /**
2304:                         * Convert '$' in resolved type signatures into '.'.
2305:                         * NOTE: This assumes that the type signature is an inner type
2306:                         * signature. This is true in most cases, but someone can define a
2307:                         * non-inner type name containing a '$'.
2308:                         */
2309:                        buffer.append('.');
2310:                        break;
2311:                    default:
2312:                        buffer.append(c);
2313:                    }
2314:                    p++;
2315:                }
2316:            }
2317:
2318:            static void appendTypeSignature(char[] string, int start,
2319:                    StringBuffer buffer, boolean compact) {
2320:                char c = string[start];
2321:                switch (c) {
2322:                case Signature.C_ARRAY:
2323:                    appendArrayTypeSignature(string, start, buffer, compact);
2324:                    break;
2325:                case Signature.C_RESOLVED:
2326:                    appendClassTypeSignature(string, start, buffer, compact);
2327:                    break;
2328:                case Signature.C_TYPE_VARIABLE:
2329:                    int e = Util.scanTypeVariableSignature(string, start);
2330:                    buffer.append(string, start + 1, e - start - 1);
2331:                    break;
2332:                case Signature.C_BOOLEAN:
2333:                    buffer.append(BOOLEAN);
2334:                    break;
2335:                case Signature.C_BYTE:
2336:                    buffer.append(BYTE);
2337:                    break;
2338:                case Signature.C_CHAR:
2339:                    buffer.append(CHAR);
2340:                    break;
2341:                case Signature.C_DOUBLE:
2342:                    buffer.append(DOUBLE);
2343:                    break;
2344:                case Signature.C_FLOAT:
2345:                    buffer.append(FLOAT);
2346:                    break;
2347:                case Signature.C_INT:
2348:                    buffer.append(INT);
2349:                    break;
2350:                case Signature.C_LONG:
2351:                    buffer.append(LONG);
2352:                    break;
2353:                case Signature.C_SHORT:
2354:                    buffer.append(SHORT);
2355:                    break;
2356:                case Signature.C_VOID:
2357:                    buffer.append(VOID);
2358:                    break;
2359:                }
2360:            }
2361:
2362:            public static String toString(char[] declaringClass,
2363:                    char[] methodName, char[] methodSignature,
2364:                    boolean includeReturnType, boolean compact) {
2365:                final boolean isConstructor = CharOperation.equals(methodName,
2366:                        INIT);
2367:                int firstParen = CharOperation.indexOf(Signature.C_PARAM_START,
2368:                        methodSignature);
2369:                if (firstParen == -1) {
2370:                    return ""; //$NON-NLS-1$
2371:                }
2372:
2373:                StringBuffer buffer = new StringBuffer(
2374:                        methodSignature.length + 10);
2375:
2376:                // decode declaring class name
2377:                // it can be either an array signature or a type signature
2378:                if (declaringClass.length > 0) {
2379:                    char[] declaringClassSignature = null;
2380:                    if (declaringClass[0] == Signature.C_ARRAY) {
2381:                        CharOperation.replace(declaringClass, '/', '.');
2382:                        declaringClassSignature = Signature
2383:                                .toCharArray(declaringClass);
2384:                    } else {
2385:                        CharOperation.replace(declaringClass, '/', '.');
2386:                        declaringClassSignature = declaringClass;
2387:                    }
2388:                    int lastIndexOfSlash = CharOperation.lastIndexOf('.',
2389:                            declaringClassSignature);
2390:                    if (compact && lastIndexOfSlash != -1) {
2391:                        buffer.append(declaringClassSignature,
2392:                                lastIndexOfSlash + 1,
2393:                                declaringClassSignature.length
2394:                                        - lastIndexOfSlash - 1);
2395:                    } else {
2396:                        buffer.append(declaringClassSignature);
2397:                    }
2398:                }
2399:
2400:                // selector
2401:                if (!isConstructor) {
2402:                    buffer.append('.');
2403:                    if (methodName != null) {
2404:                        buffer.append(methodName);
2405:                    }
2406:                }
2407:
2408:                // parameters
2409:                buffer.append('(');
2410:                char[][] pts = Signature.getParameterTypes(methodSignature);
2411:                for (int i = 0, max = pts.length; i < max; i++) {
2412:                    appendTypeSignature(pts[i], 0, buffer, compact);
2413:                    if (i != pts.length - 1) {
2414:                        buffer.append(',');
2415:                        buffer.append(' ');
2416:                    }
2417:                }
2418:                buffer.append(')');
2419:
2420:                if (!isConstructor) {
2421:                    buffer.append(" : "); //$NON-NLS-1$
2422:                    // return type
2423:                    if (includeReturnType) {
2424:                        char[] rts = Signature.getReturnType(methodSignature);
2425:                        appendTypeSignature(rts, 0, buffer, compact);
2426:                    }
2427:                }
2428:                return String.valueOf(buffer);
2429:            }
2430:
2431:            /*
2432:             * Returns the unresolved type parameter signatures of the given method
2433:             * e.g. {"QString;", "[int", "[[Qjava.util.Vector;"}
2434:             */
2435:            public static String[] typeParameterSignatures(
2436:                    AbstractMethodDeclaration method) {
2437:                Argument[] args = method.arguments;
2438:                if (args != null) {
2439:                    int length = args.length;
2440:                    String[] signatures = new String[length];
2441:                    for (int i = 0; i < args.length; i++) {
2442:                        Argument arg = args[i];
2443:                        signatures[i] = typeSignature(arg.type);
2444:                    }
2445:                    return signatures;
2446:                }
2447:                return CharOperation.NO_STRINGS;
2448:            }
2449:
2450:            /*
2451:             * Returns the unresolved type signature of the given type reference, 
2452:             * e.g. "QString;", "[int", "[[Qjava.util.Vector;"
2453:             */
2454:            public static String typeSignature(TypeReference type) {
2455:                char[][] compoundName = type.getParameterizedTypeName();
2456:                char[] typeName = CharOperation.concatWith(compoundName, '.');
2457:                String signature = Signature.createTypeSignature(typeName,
2458:                        false/*don't resolve*/);
2459:                return signature;
2460:            }
2461:
2462:            /**
2463:             * Asserts that the given method signature is valid.
2464:             */
2465:            public static void validateMethodSignature(String sig) {
2466:                Assert.isTrue(isValidMethodSignature(sig));
2467:            }
2468:
2469:            /**
2470:             * Asserts that the given type signature is valid.
2471:             */
2472:            public static void validateTypeSignature(String sig,
2473:                    boolean allowVoid) {
2474:                Assert.isTrue(isValidTypeSignature(sig, allowVoid));
2475:            }
2476:
2477:            public static void verbose(String log) {
2478:                verbose(log, System.out);
2479:            }
2480:
2481:            public static synchronized void verbose(String log,
2482:                    PrintStream printStream) {
2483:                int start = 0;
2484:                do {
2485:                    int end = log.indexOf('\n', start);
2486:                    printStream.print(Thread.currentThread());
2487:                    printStream.print(" "); //$NON-NLS-1$
2488:                    printStream.print(log.substring(start, end == -1 ? log
2489:                            .length() : end + 1));
2490:                    start = end + 1;
2491:                } while (start != 0);
2492:                printStream.println();
2493:            }
2494:
2495:            /**
2496:             * Returns true if the given name ends with one of the known java like extension.
2497:             * (implementation is not creating extra strings)
2498:             */
2499:            public final static boolean isJavaLikeFileName(String name) {
2500:                if (name == null)
2501:                    return false;
2502:                return indexOfJavaLikeExtension(name) != -1;
2503:            }
2504:
2505:            /**
2506:             * Returns true if the given name ends with one of the known java like extension.
2507:             * (implementation is not creating extra strings)
2508:             */
2509:            public final static boolean isJavaLikeFileName(char[] fileName) {
2510:                if (fileName == null)
2511:                    return false;
2512:                int fileNameLength = fileName.length;
2513:                char[][] javaLikeExtensions = getJavaLikeExtensions();
2514:                extensions: for (int i = 0, length = javaLikeExtensions.length; i < length; i++) {
2515:                    char[] extension = javaLikeExtensions[i];
2516:                    int extensionLength = extension.length;
2517:                    int extensionStart = fileNameLength - extensionLength;
2518:                    if (extensionStart - 1 < 0)
2519:                        continue;
2520:                    if (fileName[extensionStart - 1] != '.')
2521:                        continue;
2522:                    for (int j = 0; j < extensionLength; j++) {
2523:                        if (fileName[extensionStart + j] != extension[j])
2524:                            continue extensions;
2525:                    }
2526:                    return true;
2527:                }
2528:                return false;
2529:            }
2530:
2531:            /**
2532:             * Scans the given string for a type signature starting at the given index
2533:             * and returns the index of the last character.
2534:             * <pre>
2535:             * TypeSignature:
2536:             *  |  BaseTypeSignature
2537:             *  |  ArrayTypeSignature
2538:             *  |  ClassTypeSignature
2539:             *  |  TypeVariableSignature
2540:             * </pre>
2541:             * 
2542:             * @param string the signature string
2543:             * @param start the 0-based character index of the first character
2544:             * @return the 0-based character index of the last character
2545:             * @exception IllegalArgumentException if this is not a type signature
2546:             */
2547:            public static int scanTypeSignature(char[] string, int start) {
2548:                // need a minimum 1 char
2549:                if (start >= string.length) {
2550:                    throw new IllegalArgumentException();
2551:                }
2552:                char c = string[start];
2553:                switch (c) {
2554:                case Signature.C_ARRAY:
2555:                    return scanArrayTypeSignature(string, start);
2556:                case Signature.C_RESOLVED:
2557:                case Signature.C_UNRESOLVED:
2558:                    return scanClassTypeSignature(string, start);
2559:                case Signature.C_TYPE_VARIABLE:
2560:                    return scanTypeVariableSignature(string, start);
2561:                case Signature.C_BOOLEAN:
2562:                case Signature.C_BYTE:
2563:                case Signature.C_CHAR:
2564:                case Signature.C_DOUBLE:
2565:                case Signature.C_FLOAT:
2566:                case Signature.C_INT:
2567:                case Signature.C_LONG:
2568:                case Signature.C_SHORT:
2569:                case Signature.C_VOID:
2570:                    return scanBaseTypeSignature(string, start);
2571:                case Signature.C_CAPTURE:
2572:                    return scanCaptureTypeSignature(string, start);
2573:                case Signature.C_EXTENDS:
2574:                case Signature.C_SUPER:
2575:                case Signature.C_STAR:
2576:                    return scanTypeBoundSignature(string, start);
2577:                default:
2578:                    throw new IllegalArgumentException();
2579:                }
2580:            }
2581:
2582:            /**
2583:             * Scans the given string for a base type signature starting at the given index
2584:             * and returns the index of the last character.
2585:             * <pre>
2586:             * BaseTypeSignature:
2587:             *     <b>B</b> | <b>C</b> | <b>D</b> | <b>F</b> | <b>I</b>
2588:             *   | <b>J</b> | <b>S</b> | <b>V</b> | <b>Z</b>
2589:             * </pre>
2590:             * Note that although the base type "V" is only allowed in method return types,
2591:             * there is no syntactic ambiguity. This method will accept them anywhere
2592:             * without complaint.
2593:             * 
2594:             * @param string the signature string
2595:             * @param start the 0-based character index of the first character
2596:             * @return the 0-based character index of the last character
2597:             * @exception IllegalArgumentException if this is not a base type signature
2598:             */
2599:            public static int scanBaseTypeSignature(char[] string, int start) {
2600:                // need a minimum 1 char
2601:                if (start >= string.length) {
2602:                    throw new IllegalArgumentException();
2603:                }
2604:                char c = string[start];
2605:                if ("BCDFIJSVZ".indexOf(c) >= 0) { //$NON-NLS-1$
2606:                    return start;
2607:                } else {
2608:                    throw new IllegalArgumentException();
2609:                }
2610:            }
2611:
2612:            /**
2613:             * Scans the given string for an array type signature starting at the given
2614:             * index and returns the index of the last character.
2615:             * <pre>
2616:             * ArrayTypeSignature:
2617:             *     <b>[</b> TypeSignature
2618:             * </pre>
2619:             * 
2620:             * @param string the signature string
2621:             * @param start the 0-based character index of the first character
2622:             * @return the 0-based character index of the last character
2623:             * @exception IllegalArgumentException if this is not an array type signature
2624:             */
2625:            public static int scanArrayTypeSignature(char[] string, int start) {
2626:                int length = string.length;
2627:                // need a minimum 2 char
2628:                if (start >= length - 1) {
2629:                    throw new IllegalArgumentException();
2630:                }
2631:                char c = string[start];
2632:                if (c != Signature.C_ARRAY) {
2633:                    throw new IllegalArgumentException();
2634:                }
2635:
2636:                c = string[++start];
2637:                while (c == Signature.C_ARRAY) {
2638:                    // need a minimum 2 char
2639:                    if (start >= length - 1) {
2640:                        throw new IllegalArgumentException();
2641:                    }
2642:                    c = string[++start];
2643:                }
2644:                return scanTypeSignature(string, start);
2645:            }
2646:
2647:            /**
2648:             * Scans the given string for a capture of a wildcard type signature starting at the given
2649:             * index and returns the index of the last character.
2650:             * <pre>
2651:             * CaptureTypeSignature:
2652:             *     <b>!</b> TypeBoundSignature
2653:             * </pre>
2654:             * 
2655:             * @param string the signature string
2656:             * @param start the 0-based character index of the first character
2657:             * @return the 0-based character index of the last character
2658:             * @exception IllegalArgumentException if this is not a capture type signature
2659:             */
2660:            public static int scanCaptureTypeSignature(char[] string, int start) {
2661:                // need a minimum 2 char
2662:                if (start >= string.length - 1) {
2663:                    throw new IllegalArgumentException();
2664:                }
2665:                char c = string[start];
2666:                if (c != Signature.C_CAPTURE) {
2667:                    throw new IllegalArgumentException();
2668:                }
2669:                return scanTypeBoundSignature(string, start + 1);
2670:            }
2671:
2672:            /**
2673:             * Scans the given string for a type variable signature starting at the given
2674:             * index and returns the index of the last character.
2675:             * <pre>
2676:             * TypeVariableSignature:
2677:             *     <b>T</b> Identifier <b>;</b>
2678:             * </pre>
2679:             * 
2680:             * @param string the signature string
2681:             * @param start the 0-based character index of the first character
2682:             * @return the 0-based character index of the last character
2683:             * @exception IllegalArgumentException if this is not a type variable signature
2684:             */
2685:            public static int scanTypeVariableSignature(char[] string, int start) {
2686:                // need a minimum 3 chars "Tx;"
2687:                if (start >= string.length - 2) {
2688:                    throw new IllegalArgumentException();
2689:                }
2690:                // must start in "T"
2691:                char c = string[start];
2692:                if (c != Signature.C_TYPE_VARIABLE) {
2693:                    throw new IllegalArgumentException();
2694:                }
2695:                int id = scanIdentifier(string, start + 1);
2696:                c = string[id + 1];
2697:                if (c == Signature.C_SEMICOLON) {
2698:                    return id + 1;
2699:                } else {
2700:                    throw new IllegalArgumentException();
2701:                }
2702:            }
2703:
2704:            /**
2705:             * Scans the given string for an identifier starting at the given
2706:             * index and returns the index of the last character. 
2707:             * Stop characters are: ";", ":", "&lt;", "&gt;", "/", ".".
2708:             * 
2709:             * @param string the signature string
2710:             * @param start the 0-based character index of the first character
2711:             * @return the 0-based character index of the last character
2712:             * @exception IllegalArgumentException if this is not an identifier
2713:             */
2714:            public static int scanIdentifier(char[] string, int start) {
2715:                // need a minimum 1 char
2716:                if (start >= string.length) {
2717:                    throw new IllegalArgumentException();
2718:                }
2719:                int p = start;
2720:                while (true) {
2721:                    char c = string[p];
2722:                    if (c == '<' || c == '>' || c == ':' || c == ';'
2723:                            || c == '.' || c == '/') {
2724:                        return p - 1;
2725:                    }
2726:                    p++;
2727:                    if (p == string.length) {
2728:                        return p - 1;
2729:                    }
2730:                }
2731:            }
2732:
2733:            /**
2734:             * Scans the given string for a class type signature starting at the given
2735:             * index and returns the index of the last character.
2736:             * <pre>
2737:             * ClassTypeSignature:
2738:             *     { <b>L</b> | <b>Q</b> } Identifier
2739:             *           { { <b>/</b> | <b>.</b> Identifier [ <b>&lt;</b> TypeArgumentSignature* <b>&gt;</b> ] }
2740:             *           <b>;</b>
2741:             * </pre>
2742:             * Note that although all "/"-identifiers most come before "."-identifiers,
2743:             * there is no syntactic ambiguity. This method will accept them without
2744:             * complaint.
2745:             * 
2746:             * @param string the signature string
2747:             * @param start the 0-based character index of the first character
2748:             * @return the 0-based character index of the last character
2749:             * @exception IllegalArgumentException if this is not a class type signature
2750:             */
2751:            public static int scanClassTypeSignature(char[] string, int start) {
2752:                // need a minimum 3 chars "Lx;"
2753:                if (start >= string.length - 2) {
2754:                    throw new IllegalArgumentException();
2755:                }
2756:                // must start in "L" or "Q"
2757:                char c = string[start];
2758:                if (c != Signature.C_RESOLVED && c != Signature.C_UNRESOLVED) {
2759:                    return -1;
2760:                }
2761:                int p = start + 1;
2762:                while (true) {
2763:                    if (p >= string.length) {
2764:                        throw new IllegalArgumentException();
2765:                    }
2766:                    c = string[p];
2767:                    if (c == Signature.C_SEMICOLON) {
2768:                        // all done
2769:                        return p;
2770:                    } else if (c == Signature.C_GENERIC_START) {
2771:                        int e = scanTypeArgumentSignatures(string, p);
2772:                        p = e;
2773:                    } else if (c == Signature.C_DOT || c == '/') {
2774:                        int id = scanIdentifier(string, p + 1);
2775:                        p = id;
2776:                    }
2777:                    p++;
2778:                }
2779:            }
2780:
2781:            /**
2782:             * Scans the given string for a type bound signature starting at the given
2783:             * index and returns the index of the last character.
2784:             * <pre>
2785:             * TypeBoundSignature:
2786:             *     <b>[-+]</b> TypeSignature <b>;</b>
2787:             *     <b>*</b></b>
2788:             * </pre>
2789:             * 
2790:             * @param string the signature string
2791:             * @param start the 0-based character index of the first character
2792:             * @return the 0-based character index of the last character
2793:             * @exception IllegalArgumentException if this is not a type variable signature
2794:             */
2795:            public static int scanTypeBoundSignature(char[] string, int start) {
2796:                // need a minimum 1 char for wildcard
2797:                if (start >= string.length) {
2798:                    throw new IllegalArgumentException();
2799:                }
2800:                char c = string[start];
2801:                switch (c) {
2802:                case Signature.C_STAR:
2803:                    return start;
2804:                case Signature.C_SUPER:
2805:                case Signature.C_EXTENDS:
2806:                    // need a minimum 3 chars "+[I"
2807:                    if (start >= string.length - 2) {
2808:                        throw new IllegalArgumentException();
2809:                    }
2810:                    break;
2811:                default:
2812:                    // must start in "+/-"
2813:                    throw new IllegalArgumentException();
2814:
2815:                }
2816:                c = string[++start];
2817:                switch (c) {
2818:                case Signature.C_CAPTURE:
2819:                    return scanCaptureTypeSignature(string, start);
2820:                case Signature.C_SUPER:
2821:                case Signature.C_EXTENDS:
2822:                    return scanTypeBoundSignature(string, start);
2823:                case Signature.C_RESOLVED:
2824:                case Signature.C_UNRESOLVED:
2825:                    return scanClassTypeSignature(string, start);
2826:                case Signature.C_TYPE_VARIABLE:
2827:                    return scanTypeVariableSignature(string, start);
2828:                case Signature.C_ARRAY:
2829:                    return scanArrayTypeSignature(string, start);
2830:                case Signature.C_STAR:
2831:                    return start;
2832:                default:
2833:                    throw new IllegalArgumentException();
2834:                }
2835:            }
2836:
2837:            /**
2838:             * Scans the given string for a list of type argument signatures starting at
2839:             * the given index and returns the index of the last character.
2840:             * <pre>
2841:             * TypeArgumentSignatures:
2842:             *     <b>&lt;</b> TypeArgumentSignature* <b>&gt;</b>
2843:             * </pre>
2844:             * Note that although there is supposed to be at least one type argument, there
2845:             * is no syntactic ambiguity if there are none. This method will accept zero
2846:             * type argument signatures without complaint.
2847:             * 
2848:             * @param string the signature string
2849:             * @param start the 0-based character index of the first character
2850:             * @return the 0-based character index of the last character
2851:             * @exception IllegalArgumentException if this is not a list of type arguments
2852:             * signatures
2853:             */
2854:            public static int scanTypeArgumentSignatures(char[] string,
2855:                    int start) {
2856:                // need a minimum 2 char "<>"
2857:                if (start >= string.length - 1) {
2858:                    throw new IllegalArgumentException();
2859:                }
2860:                char c = string[start];
2861:                if (c != Signature.C_GENERIC_START) {
2862:                    throw new IllegalArgumentException();
2863:                }
2864:                int p = start + 1;
2865:                while (true) {
2866:                    if (p >= string.length) {
2867:                        throw new IllegalArgumentException();
2868:                    }
2869:                    c = string[p];
2870:                    if (c == Signature.C_GENERIC_END) {
2871:                        return p;
2872:                    }
2873:                    int e = scanTypeArgumentSignature(string, p);
2874:                    p = e + 1;
2875:                }
2876:            }
2877:
2878:            /**
2879:             * Scans the given string for a type argument signature starting at the given
2880:             * index and returns the index of the last character.
2881:             * <pre>
2882:             * TypeArgumentSignature:
2883:             *     <b>&#42;</b>
2884:             *  |  <b>+</b> TypeSignature
2885:             *  |  <b>-</b> TypeSignature
2886:             *  |  TypeSignature
2887:             * </pre>
2888:             * Note that although base types are not allowed in type arguments, there is
2889:             * no syntactic ambiguity. This method will accept them without complaint.
2890:             * 
2891:             * @param string the signature string
2892:             * @param start the 0-based character index of the first character
2893:             * @return the 0-based character index of the last character
2894:             * @exception IllegalArgumentException if this is not a type argument signature
2895:             */
2896:            public static int scanTypeArgumentSignature(char[] string, int start) {
2897:                // need a minimum 1 char
2898:                if (start >= string.length) {
2899:                    throw new IllegalArgumentException();
2900:                }
2901:                char c = string[start];
2902:                switch (c) {
2903:                case Signature.C_STAR:
2904:                    return start;
2905:                case Signature.C_EXTENDS:
2906:                case Signature.C_SUPER:
2907:                    return scanTypeBoundSignature(string, start);
2908:                default:
2909:                    return scanTypeSignature(string, start);
2910:                }
2911:            }
2912:
2913:            /**
2914:             * Get all type arguments from an array of signatures.
2915:             * 
2916:             * Example:
2917:             * 	For following type X<Y<Z>,V<W>,U>.A<B> signatures is:
2918:             * 	[
2919:             * 		['L','X','<','L','Y','<','L','Z',';'>',';','L','V','<','L','W',';'>',';','L','U',';',>',';'],
2920:             * 		['L','A','<','L','B',';','>',';']
2921:             * 	]
2922:             * 	@see #splitTypeLevelsSignature(String)
2923:             * 	Then, this method returns:
2924:             * 	[
2925:             * 		[
2926:             * 			['L','Y','<','L','Z',';'>',';'],
2927:             * 			['L','V','<','L','W',';'>',';'],
2928:             * 			['L','U',';']
2929:             * 		],
2930:             * 		[
2931:             * 			['L','B',';']
2932:             * 		]
2933:             * 	]
2934:             * 
2935:             * @param typeSignatures Array of signatures (one per each type levels)
2936:             * @throws IllegalArgumentException If one of provided signature is malformed
2937:             * @return char[][][] Array of type arguments for each signature
2938:             */
2939:            public final static char[][][] getAllTypeArguments(
2940:                    char[][] typeSignatures) {
2941:                if (typeSignatures == null)
2942:                    return null;
2943:                int length = typeSignatures.length;
2944:                char[][][] typeArguments = new char[length][][];
2945:                for (int i = 0; i < length; i++) {
2946:                    typeArguments[i] = Signature
2947:                            .getTypeArguments(typeSignatures[i]);
2948:                }
2949:                return typeArguments;
2950:            }
2951:
2952:            /**
2953:             * Split signatures of all levels  from a type unique key.
2954:             * 
2955:             * Example:
2956:             * 	For following type X<Y<Z>,V<W>,U>.A<B>, unique key is:
2957:             * 	"LX<LY<LZ;>;LV<LW;>;LU;>.LA<LB;>;"
2958:             * 
2959:             * 	The return splitted signatures array is:
2960:             * 	[
2961:             * 		['L','X','<','L','Y','<','L','Z',';'>',';','L','V','<','L','W',';'>',';','L','U','>',';'],
2962:             * 		['L','A','<','L','B',';','>',';']
2963:             * 
2964:             * @param typeSignature ParameterizedSourceType type signature
2965:             * @return char[][] Array of signatures for each level of given unique key
2966:             */
2967:            public final static char[][] splitTypeLevelsSignature(
2968:                    String typeSignature) {
2969:                // In case of IJavaElement signature, replace '$' by '.'
2970:                char[] source = Signature.removeCapture(typeSignature
2971:                        .toCharArray());
2972:                CharOperation.replace(source, '$', '.');
2973:
2974:                // Init counters and arrays
2975:                char[][] signatures = new char[10][];
2976:                int signaturesCount = 0;
2977:                //		int[] lengthes = new int [10];
2978:                int typeArgsCount = 0;
2979:                int paramOpening = 0;
2980:
2981:                // Scan each signature character
2982:                for (int idx = 0, ln = source.length; idx < ln; idx++) {
2983:                    switch (source[idx]) {
2984:                    case '>':
2985:                        paramOpening--;
2986:                        if (paramOpening == 0) {
2987:                            if (signaturesCount == signatures.length) {
2988:                                System
2989:                                        .arraycopy(
2990:                                                signatures,
2991:                                                0,
2992:                                                signatures = new char[signaturesCount + 10][],
2993:                                                0, signaturesCount);
2994:                            }
2995:                            typeArgsCount = 0;
2996:                        }
2997:                        break;
2998:                    case '<':
2999:                        paramOpening++;
3000:                        if (paramOpening == 1) {
3001:                            typeArgsCount = 1;
3002:                        }
3003:                        break;
3004:                    case '*':
3005:                    case ';':
3006:                        if (paramOpening == 1)
3007:                            typeArgsCount++;
3008:                        break;
3009:                    case '.':
3010:                        if (paramOpening == 0) {
3011:                            if (signaturesCount == signatures.length) {
3012:                                System
3013:                                        .arraycopy(
3014:                                                signatures,
3015:                                                0,
3016:                                                signatures = new char[signaturesCount + 10][],
3017:                                                0, signaturesCount);
3018:                            }
3019:                            signatures[signaturesCount] = new char[idx + 1];
3020:                            System.arraycopy(source, 0,
3021:                                    signatures[signaturesCount], 0, idx);
3022:                            signatures[signaturesCount][idx] = Signature.C_SEMICOLON;
3023:                            signaturesCount++;
3024:                        }
3025:                        break;
3026:                    case '/':
3027:                        source[idx] = '.';
3028:                        break;
3029:                    }
3030:                }
3031:
3032:                // Resize signatures array
3033:                char[][] typeSignatures = new char[signaturesCount + 1][];
3034:                typeSignatures[0] = source;
3035:                for (int i = 1, j = signaturesCount - 1; i <= signaturesCount; i++, j--) {
3036:                    typeSignatures[i] = signatures[j];
3037:                }
3038:                return typeSignatures;
3039:            }
3040:
3041:            /*
3042:             * Can throw IllegalArgumentException or ArrayIndexOutOfBoundsException 
3043:             */
3044:            public static String toAnchor(char[] methodSignature,
3045:                    String methodName, boolean isVarArgs) {
3046:                try {
3047:                    return new String(toAnchor(methodSignature, methodName
3048:                            .toCharArray(), isVarArgs));
3049:                } catch (IllegalArgumentException e) {
3050:                    return null;
3051:                }
3052:            }
3053:
3054:            private static char[] toAnchor(char[] methodSignature,
3055:                    char[] methodName, boolean isVargArgs) {
3056:                int firstParen = CharOperation.indexOf(Signature.C_PARAM_START,
3057:                        methodSignature);
3058:                if (firstParen == -1) {
3059:                    throw new IllegalArgumentException();
3060:                }
3061:
3062:                StringBuffer buffer = new StringBuffer(
3063:                        methodSignature.length + 10);
3064:
3065:                // selector
3066:                if (methodName != null) {
3067:                    buffer.append(methodName);
3068:                }
3069:
3070:                // parameters
3071:                buffer.append('(');
3072:                char[][] pts = Signature.getParameterTypes(methodSignature);
3073:                for (int i = 0, max = pts.length; i < max; i++) {
3074:                    if (i == max - 1) {
3075:                        appendTypeSignatureForAnchor(pts[i], 0, buffer,
3076:                                isVargArgs);
3077:                    } else {
3078:                        appendTypeSignatureForAnchor(pts[i], 0, buffer, false);
3079:                    }
3080:                    if (i != pts.length - 1) {
3081:                        buffer.append(',');
3082:                        buffer.append(' ');
3083:                    }
3084:                }
3085:                buffer.append(')');
3086:                char[] result = new char[buffer.length()];
3087:                buffer.getChars(0, buffer.length(), result, 0);
3088:                return result;
3089:            }
3090:
3091:            private static int appendTypeSignatureForAnchor(char[] string,
3092:                    int start, StringBuffer buffer, boolean isVarArgs) {
3093:                // need a minimum 1 char
3094:                if (start >= string.length) {
3095:                    throw new IllegalArgumentException();
3096:                }
3097:                char c = string[start];
3098:                if (isVarArgs) {
3099:                    switch (c) {
3100:                    case Signature.C_ARRAY:
3101:                        return appendArrayTypeSignatureForAnchor(string, start,
3102:                                buffer, true);
3103:                    case Signature.C_RESOLVED:
3104:                    case Signature.C_TYPE_VARIABLE:
3105:                    case Signature.C_BOOLEAN:
3106:                    case Signature.C_BYTE:
3107:                    case Signature.C_CHAR:
3108:                    case Signature.C_DOUBLE:
3109:                    case Signature.C_FLOAT:
3110:                    case Signature.C_INT:
3111:                    case Signature.C_LONG:
3112:                    case Signature.C_SHORT:
3113:                    case Signature.C_VOID:
3114:                    case Signature.C_STAR:
3115:                    case Signature.C_EXTENDS:
3116:                    case Signature.C_SUPER:
3117:                    case Signature.C_CAPTURE:
3118:                    default:
3119:                        throw new IllegalArgumentException(); // a var args is an array type
3120:                    }
3121:                } else {
3122:                    switch (c) {
3123:                    case Signature.C_ARRAY:
3124:                        return appendArrayTypeSignatureForAnchor(string, start,
3125:                                buffer, false);
3126:                    case Signature.C_RESOLVED:
3127:                        return appendClassTypeSignatureForAnchor(string, start,
3128:                                buffer);
3129:                    case Signature.C_TYPE_VARIABLE:
3130:                        int e = Util.scanTypeVariableSignature(string, start);
3131:                        buffer.append(string, start + 1, e - start - 1);
3132:                        return e;
3133:                    case Signature.C_BOOLEAN:
3134:                        buffer.append(BOOLEAN);
3135:                        return start;
3136:                    case Signature.C_BYTE:
3137:                        buffer.append(BYTE);
3138:                        return start;
3139:                    case Signature.C_CHAR:
3140:                        buffer.append(CHAR);
3141:                        return start;
3142:                    case Signature.C_DOUBLE:
3143:                        buffer.append(DOUBLE);
3144:                        return start;
3145:                    case Signature.C_FLOAT:
3146:                        buffer.append(FLOAT);
3147:                        return start;
3148:                    case Signature.C_INT:
3149:                        buffer.append(INT);
3150:                        return start;
3151:                    case Signature.C_LONG:
3152:                        buffer.append(LONG);
3153:                        return start;
3154:                    case Signature.C_SHORT:
3155:                        buffer.append(SHORT);
3156:                        return start;
3157:                    case Signature.C_VOID:
3158:                        buffer.append(VOID);
3159:                        return start;
3160:                    case Signature.C_CAPTURE:
3161:                        return appendCaptureTypeSignatureForAnchor(string,
3162:                                start, buffer);
3163:                    case Signature.C_STAR:
3164:                    case Signature.C_EXTENDS:
3165:                    case Signature.C_SUPER:
3166:                        return appendTypeArgumentSignatureForAnchor(string,
3167:                                start, buffer);
3168:                    default:
3169:                        throw new IllegalArgumentException();
3170:                    }
3171:                }
3172:            }
3173:
3174:            private static int appendTypeArgumentSignatureForAnchor(
3175:                    char[] string, int start, StringBuffer buffer) {
3176:                // need a minimum 1 char
3177:                if (start >= string.length) {
3178:                    throw new IllegalArgumentException();
3179:                }
3180:                char c = string[start];
3181:                switch (c) {
3182:                case Signature.C_STAR:
3183:                    return start;
3184:                case Signature.C_EXTENDS:
3185:                    return appendTypeSignatureForAnchor(string, start + 1,
3186:                            buffer, false);
3187:                case Signature.C_SUPER:
3188:                    return appendTypeSignatureForAnchor(string, start + 1,
3189:                            buffer, false);
3190:                default:
3191:                    return appendTypeSignatureForAnchor(string, start, buffer,
3192:                            false);
3193:                }
3194:            }
3195:
3196:            private static int appendCaptureTypeSignatureForAnchor(
3197:                    char[] string, int start, StringBuffer buffer) {
3198:                // need a minimum 2 char
3199:                if (start >= string.length - 1) {
3200:                    throw new IllegalArgumentException();
3201:                }
3202:                char c = string[start];
3203:                if (c != Signature.C_CAPTURE) {
3204:                    throw new IllegalArgumentException();
3205:                }
3206:                return appendTypeArgumentSignatureForAnchor(string, start + 1,
3207:                        buffer);
3208:            }
3209:
3210:            private static int appendArrayTypeSignatureForAnchor(char[] string,
3211:                    int start, StringBuffer buffer, boolean isVarArgs) {
3212:                int length = string.length;
3213:                // need a minimum 2 char
3214:                if (start >= length - 1) {
3215:                    throw new IllegalArgumentException();
3216:                }
3217:                char c = string[start];
3218:                if (c != Signature.C_ARRAY) {
3219:                    throw new IllegalArgumentException();
3220:                }
3221:
3222:                int index = start;
3223:                c = string[++index];
3224:                while (c == Signature.C_ARRAY) {
3225:                    // need a minimum 2 char
3226:                    if (index >= length - 1) {
3227:                        throw new IllegalArgumentException();
3228:                    }
3229:                    c = string[++index];
3230:                }
3231:
3232:                int e = appendTypeSignatureForAnchor(string, index, buffer,
3233:                        false);
3234:
3235:                for (int i = 1, dims = index - start; i < dims; i++) {
3236:                    buffer.append('[').append(']');
3237:                }
3238:
3239:                if (isVarArgs) {
3240:                    buffer.append('.').append('.').append('.');
3241:                } else {
3242:                    buffer.append('[').append(']');
3243:                }
3244:                return e;
3245:            }
3246:
3247:            private static int appendClassTypeSignatureForAnchor(char[] string,
3248:                    int start, StringBuffer buffer) {
3249:                // need a minimum 3 chars "Lx;"
3250:                if (start >= string.length - 2) {
3251:                    throw new IllegalArgumentException();
3252:                }
3253:                // must start in "L" or "Q"
3254:                char c = string[start];
3255:                if (c != Signature.C_RESOLVED && c != Signature.C_UNRESOLVED) {
3256:                    throw new IllegalArgumentException();
3257:                }
3258:                int p = start + 1;
3259:                while (true) {
3260:                    if (p >= string.length) {
3261:                        throw new IllegalArgumentException();
3262:                    }
3263:                    c = string[p];
3264:                    switch (c) {
3265:                    case Signature.C_SEMICOLON:
3266:                        // all done
3267:                        return p;
3268:                    case Signature.C_GENERIC_START:
3269:                        int e = scanGenericEnd(string, p + 1);
3270:                        // once we hit type arguments there are no more package prefixes
3271:                        p = e;
3272:                        break;
3273:                    case Signature.C_DOT:
3274:                        buffer.append('.');
3275:                        break;
3276:                    case '/':
3277:                        buffer.append('/');
3278:                        break;
3279:                    case Signature.C_DOLLAR:
3280:                        // once we hit "$" there are no more package prefixes
3281:                        /**
3282:                         * Convert '$' in resolved type signatures into '.'.
3283:                         * NOTE: This assumes that the type signature is an inner type
3284:                         * signature. This is true in most cases, but someone can define a
3285:                         * non-inner type name containing a '$'.
3286:                         */
3287:                        buffer.append('.');
3288:                        break;
3289:                    default:
3290:                        buffer.append(c);
3291:                    }
3292:                    p++;
3293:                }
3294:            }
3295:
3296:            private static int scanGenericEnd(char[] string, int start) {
3297:                if (string[start] == Signature.C_GENERIC_END) {
3298:                    return start;
3299:                }
3300:                int length = string.length;
3301:                int balance = 1;
3302:                start++;
3303:                while (start <= length) {
3304:                    switch (string[start]) {
3305:                    case Signature.C_GENERIC_END:
3306:                        balance--;
3307:                        if (balance == 0) {
3308:                            return start;
3309:                        }
3310:                        break;
3311:                    case Signature.C_GENERIC_START:
3312:                        balance++;
3313:                        break;
3314:                    }
3315:                    start++;
3316:                }
3317:                return start;
3318:            }
3319:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.