/******************************************************************************* * Copyright (c) 2000, 2010 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.jdt.internal.compiler.util; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.StringWriter; import java.io.UnsupportedEncodingException; import java.util.HashSet; import java.util.List; import java.util.StringTokenizer; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.ClassFile; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.batch.FileSystem; import org.eclipse.jdt.internal.compiler.batch.Main; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; import org.eclipse.jdt.internal.compiler.lookup.TagBits; import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding; import org.eclipse.jdt.internal.compiler.lookup.WildcardBinding; public class Util implements SuffixConstants { public interface Displayable { String displayString(Object o); } private static final int DEFAULT_READING_SIZE= 8192; private static final int DEFAULT_WRITING_SIZE= 1024; public final static String UTF_8= "UTF-8"; //$NON-NLS-1$ public static final String LINE_SEPARATOR= System.getProperty("line.separator"); //$NON-NLS-1$ public static final String EMPTY_STRING= new String(CharOperation.NO_CHAR); public static final int[] EMPTY_INT_ARRAY= new int[0]; /** * Build all the directories and subdirectories corresponding to the packages names into the * directory specified in parameters. * * outputPath is formed like: c:\temp\ the last character is a file separator relativeFileName * is formed like: java\lang\String.class * * * @param outputPath java.lang.String * @param relativeFileName java.lang.String * @return java.lang.String */ public static String buildAllDirectoriesInto(String outputPath, String relativeFileName) throws IOException { char fileSeparatorChar= File.separatorChar; String fileSeparator= File.separator; File f; outputPath= outputPath.replace('/', fileSeparatorChar); // these could be optimized out if we normalized paths once and for // all relativeFileName= relativeFileName.replace('/', fileSeparatorChar); String outputDirPath, fileName; int separatorIndex= relativeFileName.lastIndexOf(fileSeparatorChar); if (separatorIndex == -1) { if (outputPath.endsWith(fileSeparator)) { outputDirPath= outputPath.substring(0, outputPath.length() - 1); fileName= outputPath + relativeFileName; } else { outputDirPath= outputPath; fileName= outputPath + fileSeparator + relativeFileName; } } else { if (outputPath.endsWith(fileSeparator)) { outputDirPath= outputPath + relativeFileName.substring(0, separatorIndex); fileName= outputPath + relativeFileName; } else { outputDirPath= outputPath + fileSeparator + relativeFileName.substring(0, separatorIndex); fileName= outputPath + fileSeparator + relativeFileName; } } f= new File(outputDirPath); f.mkdirs(); if (f.isDirectory()) { return fileName; } else { // the directory creation failed for some reason - retry using // a slower algorithm so as to refine the diagnostic if (outputPath.endsWith(fileSeparator)) { outputPath= outputPath.substring(0, outputPath.length() - 1); } f= new File(outputPath); boolean checkFileType= false; if (f.exists()) { checkFileType= true; // pre-existed } else { // we have to create that directory if (!f.mkdirs()) { if (f.exists()) { // someone else created f -- need to check its type checkFileType= true; } else { // no one could create f -- complain throw new IOException(Messages.bind( Messages.output_notValidAll, f.getAbsolutePath())); } } } if (checkFileType) { if (!f.isDirectory()) { throw new IOException(Messages.bind( Messages.output_isFile, f.getAbsolutePath())); } } StringBuffer outDir= new StringBuffer(outputPath); outDir.append(fileSeparator); StringTokenizer tokenizer= new StringTokenizer(relativeFileName, fileSeparator); String token= tokenizer.nextToken(); while (tokenizer.hasMoreTokens()) { f= new File(outDir.append(token).append(fileSeparator).toString()); checkFileType= false; // reset if (f.exists()) { checkFileType= true; // this is suboptimal, but it catches corner cases // in which a regular file pre-exists } else { // we have to create that directory if (!f.mkdir()) { if (f.exists()) { // someone else created f -- need to check its type checkFileType= true; } else { // no one could create f -- complain throw new IOException(Messages.bind( Messages.output_notValid, outDir.substring(outputPath.length() + 1, outDir.length() - 1), outputPath)); } } } if (checkFileType) { if (!f.isDirectory()) { throw new IOException(Messages.bind( Messages.output_isFile, f.getAbsolutePath())); } } token= tokenizer.nextToken(); } // token contains the last one return outDir.append(token).toString(); } } /** * Returns the given bytes as a char array using a given encoding (null means platform default). */ public static char[] bytesToChar(byte[] bytes, String encoding) throws IOException { return getInputStreamAsCharArray(new ByteArrayInputStream(bytes), bytes.length, encoding); } /** * Returns the outer most enclosing type's visibility for the given TypeDeclaration and * visibility based on compiler options. */ public static int computeOuterMostVisibility(TypeDeclaration typeDeclaration, int visibility) { while (typeDeclaration != null) { switch (typeDeclaration.modifiers & ExtraCompilerModifiers.AccVisibilityMASK) { case ClassFileConstants.AccPrivate: visibility= ClassFileConstants.AccPrivate; break; case ClassFileConstants.AccDefault: if (visibility != ClassFileConstants.AccPrivate) { visibility= ClassFileConstants.AccDefault; } break; case ClassFileConstants.AccProtected: if (visibility == ClassFileConstants.AccPublic) { visibility= ClassFileConstants.AccProtected; } break; } typeDeclaration= typeDeclaration.enclosingType; } return visibility; } /** * Returns the contents of the given file as a byte array. * * @throws IOException if a problem occured reading the file. */ public static byte[] getFileByteContent(File file) throws IOException { InputStream stream= null; try { stream= new BufferedInputStream(new FileInputStream(file)); return getInputStreamAsByteArray(stream, (int)file.length()); } finally { if (stream != null) { try { stream.close(); } catch (IOException e) { // ignore } } } } /** * Returns the contents of the given file as a char array. When encoding is null, then the * platform default one is used * * @throws IOException if a problem occured reading the file. */ public static char[] getFileCharContent(File file, String encoding) throws IOException { InputStream stream= null; try { stream= new FileInputStream(file); return getInputStreamAsCharArray(stream, (int)file.length(), encoding); } finally { if (stream != null) { try { stream.close(); } catch (IOException e) { // ignore } } } } private static FileOutputStream getFileOutputStream(boolean generatePackagesStructure, String outputPath, String relativeFileName) throws IOException { if (generatePackagesStructure) { return new FileOutputStream(new File(buildAllDirectoriesInto(outputPath, relativeFileName))); } else { String fileName= null; char fileSeparatorChar= File.separatorChar; String fileSeparator= File.separator; // First we ensure that the outputPath exists outputPath= outputPath.replace('/', fileSeparatorChar); // To be able to pass the mkdirs() method we need to remove the extra file separator at the end of the outDir name int indexOfPackageSeparator= relativeFileName.lastIndexOf(fileSeparatorChar); if (indexOfPackageSeparator == -1) { if (outputPath.endsWith(fileSeparator)) { fileName= outputPath + relativeFileName; } else { fileName= outputPath + fileSeparator + relativeFileName; } } else { int length= relativeFileName.length(); if (outputPath.endsWith(fileSeparator)) { fileName= outputPath + relativeFileName.substring(indexOfPackageSeparator + 1, length); } else { fileName= outputPath + fileSeparator + relativeFileName.substring(indexOfPackageSeparator + 1, length); } } return new FileOutputStream(new File(fileName)); } } /* * NIO support to get input stream as byte array. * Not used as with JDK 1.4.2 this support is slower than standard IO one... * Keep it as comment for future in case of next JDK versions improve performance * in this area... * public static byte[] getInputStreamAsByteArray(FileInputStream stream, int length) throws IOException { FileChannel channel = stream.getChannel(); int size = (int)channel.size(); if (length >= 0 && length < size) size = length; byte[] contents = new byte[size]; ByteBuffer buffer = ByteBuffer.wrap(contents); channel.read(buffer); return contents; } */ /** * Returns the given input stream's contents as a byte array. If a length is specified (ie. if * length != -1), only length bytes are returned. Otherwise all bytes in the stream are * returned. Note this doesn't close the stream. * * @throws IOException if a problem occured reading the stream. */ public static byte[] getInputStreamAsByteArray(InputStream stream, int length) throws IOException { byte[] contents; if (length == -1) { contents= new byte[0]; int contentsLength= 0; int amountRead= -1; do { int amountRequested= Math.max(stream.available(), DEFAULT_READING_SIZE); // read at least 8K // resize contents if needed if (contentsLength + amountRequested > contents.length) { System.arraycopy( contents, 0, contents= new byte[contentsLength + amountRequested], 0, contentsLength); } // read as many bytes as possible amountRead= stream.read(contents, contentsLength, amountRequested); if (amountRead > 0) { // remember length of contents contentsLength+= amountRead; } } while (amountRead != -1); // resize contents if necessary if (contentsLength < contents.length) { System.arraycopy( contents, 0, contents= new byte[contentsLength], 0, contentsLength); } } else { contents= new byte[length]; int len= 0; int readSize= 0; while ((readSize != -1) && (len != length)) { // See PR 1FMS89U // We record first the read size. In this case len is the actual read size. len+= readSize; readSize= stream.read(contents, len, length - len); } } return contents; } /* * NIO support to get input stream as char array. * Not used as with JDK 1.4.2 this support is slower than standard IO one... * Keep it as comment for future in case of next JDK versions improve performance * in this area... public static char[] getInputStreamAsCharArray(FileInputStream stream, int length, String encoding) throws IOException { FileChannel channel = stream.getChannel(); int size = (int)channel.size(); if (length >= 0 && length < size) size = length; Charset charset = encoding==null?systemCharset:Charset.forName(encoding); if (charset != null) { MappedByteBuffer bbuffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, size); CharsetDecoder decoder = charset.newDecoder(); CharBuffer buffer = decoder.decode(bbuffer); char[] contents = new char[buffer.limit()]; buffer.get(contents); return contents; } throw new UnsupportedCharsetException(SYSTEM_FILE_ENCODING); } */ /** * Returns the given input stream's contents as a character array. If a length is specified (ie. * if length != -1), this represents the number of bytes in the stream. Note this doesn't close * the stream. * * @throws IOException if a problem occured reading the stream. */ public static char[] getInputStreamAsCharArray(InputStream stream, int length, String encoding) throws IOException { BufferedReader reader= null; try { reader= encoding == null ? new BufferedReader(new InputStreamReader(stream)) : new BufferedReader(new InputStreamReader(stream, encoding)); } catch (UnsupportedEncodingException e) { // encoding is not supported reader= new BufferedReader(new InputStreamReader(stream)); } char[] contents; int totalRead= 0; if (length == -1) { contents= CharOperation.NO_CHAR; } else { // length is a good guess when the encoding produces less or the same amount of characters than the file length contents= new char[length]; // best guess } while (true) { int amountRequested; if (totalRead < length) { // until known length is met, reuse same array sized eagerly amountRequested= length - totalRead; } else { // reading beyond known length int current= reader.read(); if (current < 0) break; amountRequested= Math.max(stream.available(), DEFAULT_READING_SIZE); // read at least 8K // resize contents if needed if (totalRead + 1 + amountRequested > contents.length) System.arraycopy(contents, 0, contents= new char[totalRead + 1 + amountRequested], 0, totalRead); // add current character contents[totalRead++]= (char)current; // coming from totalRead==length } // read as many chars as possible int amountRead= reader.read(contents, totalRead, amountRequested); if (amountRead < 0) break; totalRead+= amountRead; } // Do not keep first character for UTF-8 BOM encoding int start= 0; if (totalRead > 0 && UTF_8.equals(encoding)) { if (contents[0] == 0xFEFF) { // if BOM char then skip totalRead--; start= 1; } } // resize contents if necessary if (totalRead < contents.length) System.arraycopy(contents, start, contents= new char[totalRead], 0, totalRead); return contents; } /** * Returns a one line summary for an exception (extracted from its stacktrace: name + first * frame) * * @param exception * @return one line summary for an exception */ public static String getExceptionSummary(Throwable exception) { StringWriter stringWriter= new StringWriter(); exception.printStackTrace(new PrintWriter(stringWriter)); StringBuffer buffer= stringWriter.getBuffer(); StringBuffer exceptionBuffer= new StringBuffer(50); exceptionBuffer.append(exception.toString()); // only keep leading frame portion of the trace (i.e. line no. 2 from the stacktrace) lookupLine2: for (int i= 0, lineSep= 0, max= buffer.length(), line2Start= 0; i < max; i++) { switch (buffer.charAt(i)) { case '\n': case '\r': if (line2Start > 0) { exceptionBuffer.append(' ').append(buffer.substring(line2Start, i)); break lookupLine2; } lineSep++; break; case ' ': case '\t': break; default: if (lineSep > 0) { line2Start= i; lineSep= 0; } break; } } return exceptionBuffer.toString(); } public static int getLineNumber(int position, int[] lineEnds, int g, int d) { if (lineEnds == null) return 1; if (d == -1) return 1; int m= g, start; while (g <= d) { m= g + (d - g) / 2; if (position < (start= lineEnds[m])) { d= m - 1; } else if (position > start) { g= m + 1; } else { return m + 1; } } if (position < lineEnds[m]) { return m + 1; } return m + 2; } /** * Returns the contents of the given zip entry as a byte array. * * @throws IOException if a problem occured reading the zip entry. */ public static byte[] getZipEntryByteContent(ZipEntry ze, ZipFile zip) throws IOException { InputStream stream= null; try { InputStream inputStream= zip.getInputStream(ze); if (inputStream == null) throw new IOException("Invalid zip entry name : " + ze.getName()); //$NON-NLS-1$ stream= new BufferedInputStream(inputStream); return getInputStreamAsByteArray(stream, (int)ze.getSize()); } finally { if (stream != null) { try { stream.close(); } catch (IOException e) { // ignore } } } } /** * Returns whether the given name is potentially a zip archive file name (it has a file * extension and it is not ".java" nor ".class") */ public final static boolean isPotentialZipArchive(String name) { int lastDot= name.lastIndexOf('.'); if (lastDot == -1) return false; // no file extension, it cannot be a zip archive name if (name.lastIndexOf(File.separatorChar) > lastDot) return false; // dot was before the last file separator, it cannot be a zip archive name int length= name.length(); int extensionLength= length - lastDot - 1; if (extensionLength == EXTENSION_java.length()) { for (int i= extensionLength - 1; i >= 0; i--) { if (Character.toLowerCase(name.charAt(length - extensionLength + i)) != EXTENSION_java.charAt(i)) { break; // not a ".java" file, check ".class" file case below } if (i == 0) { return false; // it is a ".java" file, it cannot be a zip archive name } } } if (extensionLength == EXTENSION_class.length()) { for (int i= extensionLength - 1; i >= 0; i--) { if (Character.toLowerCase(name.charAt(length - extensionLength + i)) != EXTENSION_class.charAt(i)) { return true; // not a ".class" file, so this is a potential archive name } } return false; // it is a ".class" file, it cannot be a zip archive name } return true; // it is neither a ".java" file nor a ".class" file, so this is a potential archive name } /** * Returns true iff str.toLowerCase().endsWith(".class") implementation is not creating extra * strings. */ public final static boolean isClassFileName(char[] name) { int nameLength= name == null ? 0 : name.length; int suffixLength= SUFFIX_CLASS.length; if (nameLength < suffixLength) return false; for (int i= 0, offset= nameLength - suffixLength; i < suffixLength; i++) { char c= name[offset + i]; if (c != SUFFIX_class[i] && c != SUFFIX_CLASS[i]) return false; } return true; } /** * Returns true iff str.toLowerCase().endsWith(".class") implementation is not creating extra * strings. */ public final static boolean isClassFileName(String name) { int nameLength= name == null ? 0 : name.length(); int suffixLength= SUFFIX_CLASS.length; if (nameLength < suffixLength) return false; for (int i= 0; i < suffixLength; i++) { char c= name.charAt(nameLength - i - 1); int suffixIndex= suffixLength - i - 1; if (c != SUFFIX_class[suffixIndex] && c != SUFFIX_CLASS[suffixIndex]) return false; } return true; } /* TODO (philippe) should consider promoting it to CharOperation * Returns whether the given resource path matches one of the inclusion/exclusion * patterns. * NOTE: should not be asked directly using pkg root pathes * @see IClasspathEntry#getInclusionPatterns * @see IClasspathEntry#getExclusionPatterns */ public final static boolean isExcluded(char[] path, char[][] inclusionPatterns, char[][] exclusionPatterns, boolean isFolderPath) { if (inclusionPatterns == null && exclusionPatterns == null) return false; inclusionCheck: if (inclusionPatterns != null) { for (int i= 0, length= inclusionPatterns.length; i < length; i++) { char[] pattern= inclusionPatterns[i]; char[] folderPattern= pattern; if (isFolderPath) { int lastSlash= CharOperation.lastIndexOf('/', pattern); if (lastSlash != -1 && lastSlash != pattern.length - 1) { // trailing slash -> adds '**' for free (see http://ant.apache.org/manual/dirtasks.html) int star= CharOperation.indexOf('*', pattern, lastSlash); if ((star == -1 || star >= pattern.length - 1 || pattern[star + 1] != '*')) { folderPattern= CharOperation.subarray(pattern, 0, lastSlash); } } } if (CharOperation.pathMatch(folderPattern, path, true, '/')) { break inclusionCheck; } } return true; // never included } if (isFolderPath) { path= CharOperation.concat(path, new char[] { '*' }, '/'); } if (exclusionPatterns != null) { for (int i= 0, length= exclusionPatterns.length; i < length; i++) { if (CharOperation.pathMatch(exclusionPatterns[i], path, true, '/')) { return true; } } } return false; } /** * Returns true iff str.toLowerCase().endsWith(".java") implementation is not creating extra * strings. */ public final static boolean isJavaFileName(char[] name) { int nameLength= name == null ? 0 : name.length; int suffixLength= SUFFIX_JAVA.length; if (nameLength < suffixLength) return false; for (int i= 0, offset= nameLength - suffixLength; i < suffixLength; i++) { char c= name[offset + i]; if (c != SUFFIX_java[i] && c != SUFFIX_JAVA[i]) return false; } return true; } /** * Returns true iff str.toLowerCase().endsWith(".java") implementation is not creating extra * strings. */ public final static boolean isJavaFileName(String name) { int nameLength= name == null ? 0 : name.length(); int suffixLength= SUFFIX_JAVA.length; if (nameLength < suffixLength) return false; for (int i= 0; i < suffixLength; i++) { char c= name.charAt(nameLength - i - 1); int suffixIndex= suffixLength - i - 1; if (c != SUFFIX_java[suffixIndex] && c != SUFFIX_JAVA[suffixIndex]) return false; } return true; } public static void reverseQuickSort(char[][] list, int left, int right) { int original_left= left; int original_right= right; char[] mid= list[(right + left) / 2]; do { while (CharOperation.compareTo(list[left], mid) > 0) { left++; } while (CharOperation.compareTo(mid, list[right]) > 0) { right--; } if (left <= right) { char[] tmp= list[left]; list[left]= list[right]; list[right]= tmp; left++; right--; } } while (left <= right); if (original_left < right) { reverseQuickSort(list, original_left, right); } if (left < original_right) { reverseQuickSort(list, left, original_right); } } public static void reverseQuickSort(char[][] list, int left, int right, int[] result) { int original_left= left; int original_right= right; char[] mid= list[(right + left) / 2]; do { while (CharOperation.compareTo(list[left], mid) > 0) { left++; } while (CharOperation.compareTo(mid, list[right]) > 0) { right--; } if (left <= right) { char[] tmp= list[left]; list[left]= list[right]; list[right]= tmp; int temp= result[left]; result[left]= result[right]; result[right]= temp; left++; right--; } } while (left <= right); if (original_left < right) { reverseQuickSort(list, original_left, right, result); } if (left < original_right) { reverseQuickSort(list, left, original_right, result); } } /** * INTERNAL USE-ONLY Search the column number corresponding to a specific position */ public static final int searchColumnNumber(int[] startLineIndexes, int lineNumber, int position) { switch (lineNumber) { case 1: return position + 1; case 2: return position - startLineIndexes[0]; default: int line= lineNumber - 2; int length= startLineIndexes.length; if (line >= length) { return position - startLineIndexes[length - 1]; } return position - startLineIndexes[line]; } } /** * Converts a boolean value into Boolean. * * @param bool The boolean to convert * @return The corresponding Boolean object (TRUE or FALSE). */ public static Boolean toBoolean(boolean bool) { if (bool) { return Boolean.TRUE; } else { return Boolean.FALSE; } } /** * Converts an array of Objects into String. */ public static String toString(Object[] objects) { return toString(objects, new Displayable() { public String displayString(Object o) { if (o == null) return "null"; //$NON-NLS-1$ return o.toString(); } }); } /** * Converts an array of Objects into String. */ public static String toString(Object[] objects, Displayable renderer) { if (objects == null) return ""; //$NON-NLS-1$ StringBuffer buffer= new StringBuffer(10); for (int i= 0; i < objects.length; i++) { if (i > 0) buffer.append(", "); //$NON-NLS-1$ buffer.append(renderer.displayString(objects[i])); } return buffer.toString(); } /** * outputPath is formed like: c:\temp\ the last character is a file separator relativeFileName * is formed like: java\lang\String.class * * @param generatePackagesStructure a flag to know if the packages structure has to be * generated. * @param outputPath the given output directory * @param relativeFileName the given relative file name * @param classFile the given classFile to write * */ public static void writeToDisk(boolean generatePackagesStructure, String outputPath, String relativeFileName, ClassFile classFile) throws IOException { FileOutputStream file= getFileOutputStream(generatePackagesStructure, outputPath, relativeFileName); /* use java.nio to write if (true) { FileChannel ch = file.getChannel(); try { ByteBuffer buffer = ByteBuffer.allocate(classFile.headerOffset + classFile.contentsOffset); buffer.put(classFile.header, 0, classFile.headerOffset); buffer.put(classFile.contents, 0, classFile.contentsOffset); buffer.flip(); while (true) { if (ch.write(buffer) == 0) break; } } finally { ch.close(); } return; } */ BufferedOutputStream output= new BufferedOutputStream(file, DEFAULT_WRITING_SIZE); // BufferedOutputStream output = new BufferedOutputStream(file); try { // if no IOException occured, output cannot be null output.write(classFile.header, 0, classFile.headerOffset); output.write(classFile.contents, 0, classFile.contentsOffset); output.flush(); } catch (IOException e) { throw e; } finally { output.close(); } } public static void recordNestedType(ClassFile classFile, TypeBinding typeBinding) { if (classFile.visitedTypes == null) { classFile.visitedTypes= new HashSet(3); } else if (classFile.visitedTypes.contains(typeBinding)) { // type is already visited return; } classFile.visitedTypes.add(typeBinding); if (typeBinding.isParameterizedType() && ((typeBinding.tagBits & TagBits.ContainsNestedTypeReferences) != 0)) { ParameterizedTypeBinding parameterizedTypeBinding= (ParameterizedTypeBinding)typeBinding; ReferenceBinding genericType= parameterizedTypeBinding.genericType(); if ((genericType.tagBits & TagBits.ContainsNestedTypeReferences) != 0) { recordNestedType(classFile, genericType); } TypeBinding[] arguments= parameterizedTypeBinding.arguments; if (arguments != null) { for (int j= 0, max2= arguments.length; j < max2; j++) { TypeBinding argument= arguments[j]; if (argument.isWildcard()) { WildcardBinding wildcardBinding= (WildcardBinding)argument; TypeBinding bound= wildcardBinding.bound; if (bound != null && ((bound.tagBits & TagBits.ContainsNestedTypeReferences) != 0)) { recordNestedType(classFile, bound); } ReferenceBinding superclass= wildcardBinding.superclass(); if (superclass != null && ((superclass.tagBits & TagBits.ContainsNestedTypeReferences) != 0)) { recordNestedType(classFile, superclass); } ReferenceBinding[] superInterfaces= wildcardBinding.superInterfaces(); if (superInterfaces != null) { for (int k= 0, max3= superInterfaces.length; k < max3; k++) { ReferenceBinding superInterface= superInterfaces[k]; if ((superInterface.tagBits & TagBits.ContainsNestedTypeReferences) != 0) { recordNestedType(classFile, superInterface); } } } } else if ((argument.tagBits & TagBits.ContainsNestedTypeReferences) != 0) { recordNestedType(classFile, argument); } } } } else if (typeBinding.isTypeVariable() && ((typeBinding.tagBits & TagBits.ContainsNestedTypeReferences) != 0)) { TypeVariableBinding typeVariableBinding= (TypeVariableBinding)typeBinding; TypeBinding upperBound= typeVariableBinding.upperBound(); if (upperBound != null && ((upperBound.tagBits & TagBits.ContainsNestedTypeReferences) != 0)) { recordNestedType(classFile, upperBound); } TypeBinding[] upperBounds= typeVariableBinding.otherUpperBounds(); if (upperBounds != null) { for (int k= 0, max3= upperBounds.length; k < max3; k++) { TypeBinding otherUpperBound= upperBounds[k]; if ((otherUpperBound.tagBits & TagBits.ContainsNestedTypeReferences) != 0) { recordNestedType(classFile, otherUpperBound); } } } } else if (typeBinding.isNestedType()) { classFile.recordInnerClasses(typeBinding); } } /* * External API */ public static File getJavaHome() { String javaHome= System.getProperty("java.home");//$NON-NLS-1$ if (javaHome != null) { File javaHomeFile= new File(javaHome); if (javaHomeFile.exists()) { return javaHomeFile; } } return null; } public static void collectRunningVMBootclasspath(List bootclasspaths) { /* no bootclasspath specified * we can try to retrieve the default librairies of the VM used to run * the batch compiler */ String javaversion= System.getProperty("java.version");//$NON-NLS-1$ if (javaversion != null && javaversion.equalsIgnoreCase("1.1.8")) { //$NON-NLS-1$ throw new IllegalStateException(); } /* * Handle >= JDK 1.2.2 settings: retrieve the bootclasspath */ // check bootclasspath properties for Sun, JRockit and Harmony VMs String bootclasspathProperty= System.getProperty("sun.boot.class.path"); //$NON-NLS-1$ if ((bootclasspathProperty == null) || (bootclasspathProperty.length() == 0)) { // IBM J9 VMs bootclasspathProperty= System.getProperty("vm.boot.class.path"); //$NON-NLS-1$ if ((bootclasspathProperty == null) || (bootclasspathProperty.length() == 0)) { // Harmony using IBM VME bootclasspathProperty= System.getProperty("org.apache.harmony.boot.class.path"); //$NON-NLS-1$ } } if ((bootclasspathProperty != null) && (bootclasspathProperty.length() != 0)) { StringTokenizer tokenizer= new StringTokenizer(bootclasspathProperty, File.pathSeparator); String token; while (tokenizer.hasMoreTokens()) { token= tokenizer.nextToken(); FileSystem.Classpath currentClasspath= FileSystem.getClasspath(token, null, null); if (currentClasspath != null) { bootclasspaths.add(currentClasspath); } } } else { // try to get all jars inside the lib folder of the java home final File javaHome= getJavaHome(); if (javaHome != null) { File[] directoriesToCheck= null; if (System.getProperty("os.name").startsWith("Mac")) {//$NON-NLS-1$//$NON-NLS-2$ directoriesToCheck= new File[] { new File(javaHome, "../Classes"), //$NON-NLS-1$ }; } else { // fall back to try to retrieve them out of the lib directory directoriesToCheck= new File[] { new File(javaHome, "lib") //$NON-NLS-1$ }; } File[][] systemLibrariesJars= Main.getLibrariesFiles(directoriesToCheck); if (systemLibrariesJars != null) { for (int i= 0, max= systemLibrariesJars.length; i < max; i++) { File[] current= systemLibrariesJars[i]; if (current != null) { for (int j= 0, max2= current.length; j < max2; j++) { FileSystem.Classpath classpath= FileSystem.getClasspath(current[j].getAbsolutePath(), null, false, null, null); if (classpath != null) { bootclasspaths.add(classpath); } } } } } } } } }