From: crawshaw Date: Mon, 22 Nov 2004 19:26:03 +0000 (+0000) Subject: import eclipse core compiler plugin (version 3.0.1) X-Git-Url: http://git.megacz.com/?p=org.ibex.tool.git;a=commitdiff_plain;h=63f02266147d91666343de3d017ec7fd5fc700c6 import eclipse core compiler plugin (version 3.0.1) darcs-hash:20041122192603-2eb37-b97550ed0c0b3bef299f075cda45c2b08e013a17.gz --- diff --git a/src/java/org/eclipse/jdt/core/compiler/CharOperation.java b/src/java/org/eclipse/jdt/core/compiler/CharOperation.java new file mode 100644 index 0000000..07d23e3 --- /dev/null +++ b/src/java/org/eclipse/jdt/core/compiler/CharOperation.java @@ -0,0 +1,2686 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.compiler; + +/** + * This class is a collection of helper methods to manipulate char arrays. + * + * @since 2.1 + */ +public final class CharOperation { + + /** + * Constant for an empty char array + */ + public static final char[] NO_CHAR = new char[0]; + + /** + * Constant for an empty char array with two dimensions. + */ + public static final char[][] NO_CHAR_CHAR = new char[0][]; + + /** + * Answers a new array with appending the suffix character at the end of the array. + *
+ *
+ * For example:
+ *
    + *
  1. +	 *    array = { 'a', 'b' }
    +	 *    suffix = 'c'
    +	 *    => result = { 'a', 'b' , 'c' }
    +	 * 
    + *
  2. + *
  3. +	 *    array = null
    +	 *    suffix = 'c'
    +	 *    => result = { 'c' }
    +	 * 
  4. + *
+ * + * @param array the array that is concanated with the suffix character + * @param suffix the suffix character + * @return the new array + */ + public static final char[] append(char[] array, char suffix) { + if (array == null) + return new char[] { suffix }; + int length = array.length; + System.arraycopy(array, 0, array = new char[length + 1], 0, length); + array[length] = suffix; + return array; + } + /** + * Append the given subarray to the target array starting at the given index in the target array. + * The start of the subarray is inclusive, the end is exclusive. + * Answers a new target array if it needs to grow, otherwise answers the same target array. + *
+ * For example:
+ *
    + *
  1. +	 *    target = { 'a', 'b', '0' }
    +	 *    index = 2
    +	 *    array = { 'c', 'd' }
    +	 *    start = 0
    +	 *    end = 1
    +	 *    => result = { 'a', 'b' , 'c' }
    +	 * 
    + *
  2. + *
  3. +	 *    target = { 'a', 'b' }
    +	 *    index = 2
    +	 *    array = { 'c', 'd' }
    +	 *    start = 0
    +	 *    end = 1
    +	 *    => result = { 'a', 'b' , 'c', '0', '0' , '0' } (new array)
    +	 * 
  4. + *
  5. +	 *    target = { 'a', 'b', 'c' }
    +	 *    index = 1
    +	 *    array = { 'c', 'd', 'e', 'f' }
    +	 *    start = 1
    +	 *    end = 4
    +	 *    => result = { 'a', 'd' , 'e', 'f', '0', '0', '0', '0' } (new array)
    +	 * 
  6. + *
+ * + * @param target the given target + * @param index the given index + * @param array the given array + * @param start the given start index + * @param end the given end index + * + * @return the new array + * @throws NullPointerException if the target array is null + */ + public static final char[] append(char[] target, int index, char[] array, int start, int end) { + int targetLength = target.length; + int subLength = end-start; + int newTargetLength = subLength+index; + if (newTargetLength > targetLength) { + System.arraycopy(target, 0, target = new char[newTargetLength*2], 0, index); + } + System.arraycopy(array, start, target, index, subLength); + return target; + } + + /** + * Answers the concatenation of the two arrays. It answers null if the two arrays are null. + * If the first array is null, then the second array is returned. + * If the second array is null, then the first array is returned. + *
+ *
+ * For example: + *
    + *
  1. +	 *    first = null
    +	 *    second = null
    +	 *    => result = null
    +	 * 
    + *
  2. + *
  3. +	 *    first = { { ' a' } }
    +	 *    second = null
    +	 *    => result = { { ' a' } }
    +	 * 
    + *
  4. + *
  5. +	 *    first = null
    +	 *    second = { { ' a' } }
    +	 *    => result = { { ' a' } }
    +	 * 
    + *
  6. + *
  7. +	 *    first = { { ' b' } }
    +	 *    second = { { ' a' } }
    +	 *    => result = { { ' b' }, { ' a' } }
    +	 * 
    + *
  8. + *
+ * + * @param first the first array to concatenate + * @param second the second array to concatenate + * @return the concatenation of the two arrays, or null if the two arrays are null. + */ + public static final char[][] arrayConcat(char[][] first, char[][] second) { + if (first == null) + return second; + if (second == null) + return first; + + int length1 = first.length; + int length2 = second.length; + char[][] result = new char[length1 + length2][]; + System.arraycopy(first, 0, result, 0, length1); + System.arraycopy(second, 0, result, length1, length2); + return result; + } + /** + * Returns the char arrays as an array of Strings + * + * @param charArrays the char array to convert + * @return the char arrays as an array of Strings or null if the given char arrays is null. + * @since 3.0 + */ + public static String[] charArrayToStringArray(char[][] charArrays) { + if (charArrays == null) { + return null; + } + String[] strings= new String[charArrays.length]; + for (int i= 0; i < charArrays.length; i++) { + strings[i]= new String(charArrays[i]); + } + return strings; + } + /** + * Returns the char array as a String + + * @param charArray the char array to convert + * @return the char array as a String or null if the given char array is null. + * @since 3.0 + */ + public static String charToString(char[] charArray) { + if (charArray == null) return null; + return new String(charArray); + } + + /** + * Answers a new array adding the second array at the end of first array. + * It answers null if the first and second are null. + * If the first array is null, then a new array char[][] is created with second. + * If the second array is null, then the first array is returned. + *
+ *
+ * For example: + *
    + *
  1. +	 *    first = null
    +	 *    second = { 'a' }
    +	 *    => result = { { ' a' } }
    +	 * 
    + *
  2. +	 *    first = { { ' a' } }
    +	 *    second = null
    +	 *    => result = { { ' a' } }
    +	 * 
    + *
  3. + *
  4. +	 *    first = { { ' a' } }
    +	 *    second = { ' b' }
    +	 *    => result = { { ' a' } , { ' b' } }
    +	 * 
    + *
  5. + *
+ * + * @param first the first array to concatenate + * @param second the array to add at the end of the first array + * @return a new array adding the second array at the end of first array, or null if the two arrays are null. + */ + public static final char[][] arrayConcat(char[][] first, char[] second) { + if (second == null) + return first; + if (first == null) + return new char[][] { second }; + + int length = first.length; + char[][] result = new char[length + 1][]; + System.arraycopy(first, 0, result, 0, length); + result[length] = second; + return result; + } + + /** + * Compares the contents of the two arrays array and prefix. Returns + * + *

+ * For example: + *

    + *
  1. +	 *    array = null
    +	 *    prefix = null
    +	 *    => result = NullPointerException
    +	 * 
    + *
  2. + *
  3. +	 *    array = { 'a', 'b', 'c', 'd', 'e' }
    +	 *    prefix = { 'a', 'b', 'c'}
    +	 *    => result = 0
    +	 * 
    + *
  4. + *
  5. +	 *    array = { 'a', 'b', 'c', 'd', 'e' }
    +	 *    prefix = { 'a', 'B', 'c'}
    +	 *    => result = 32
    +	 * 
    + *
  6. + *
  7. +	 *    array = { 'd', 'b', 'c', 'd', 'e' }
    +	 *    prefix = { 'a', 'b', 'c'}
    +	 *    => result = 3
    +	 * 
    + *
  8. + *
  9. +	 *    array = { 'a', 'b', 'c', 'd', 'e' }
    +	 *    prefix = { 'd', 'b', 'c'}
    +	 *    => result = -3
    +	 * 
    + *
  10. + *
  11. +	 *    array = { 'a', 'a', 'c', 'd', 'e' }
    +	 *    prefix = { 'a', 'e', 'c'}
    +	 *    => result = -4
    +	 * 
    + *
  12. + *
+ *

+ * + * @param array the given array + * @param prefix the given prefix + * @return the result of the comparison (>=0 if array>prefix) + * @throws NullPointerException if either array or prefix is null + */ + public static final int compareWith(char[] array, char[] prefix) { + int arrayLength = array.length; + int prefixLength = prefix.length; + int min = Math.min(arrayLength, prefixLength); + int i = 0; + while (min-- != 0) { + char c1 = array[i]; + char c2 = prefix[i++]; + if (c1 != c2) + return c1 - c2; + } + if (prefixLength == i) + return 0; + return -1; // array is shorter than prefix (e.g. array:'ab' < prefix:'abc'). + } + + /** + * Answers the concatenation of the two arrays. It answers null if the two arrays are null. + * If the first array is null, then the second array is returned. + * If the second array is null, then the first array is returned. + *
+ *
+ * For example: + *
    + *
  1. +	 *    first = null
    +	 *    second = { 'a' }
    +	 *    => result = { ' a' }
    +	 * 
    + *
  2. + *
  3. +	 *    first = { ' a' }
    +	 *    second = null
    +	 *    => result = { ' a' }
    +	 * 
    + *
  4. + *
  5. +	 *    first = { ' a' }
    +	 *    second = { ' b' }
    +	 *    => result = { ' a' , ' b' }
    +	 * 
    + *
  6. + *
+ * + * @param first the first array to concatenate + * @param second the second array to concatenate + * @return the concatenation of the two arrays, or null if the two arrays are null. + */ + public static final char[] concat(char[] first, char[] second) { + if (first == null) + return second; + if (second == null) + return first; + + int length1 = first.length; + int length2 = second.length; + char[] result = new char[length1 + length2]; + System.arraycopy(first, 0, result, 0, length1); + System.arraycopy(second, 0, result, length1, length2); + return result; + } + + /** + * Answers the concatenation of the three arrays. It answers null if the three arrays are null. + * If first is null, it answers the concatenation of second and third. + * If second is null, it answers the concatenation of first and third. + * If third is null, it answers the concatenation of first and second. + *
+ *
+ * For example: + *
    + *
  1. +	 *    first = null
    +	 *    second = { 'a' }
    +	 *    third = { 'b' }
    +	 *    => result = { ' a', 'b' }
    +	 * 
    + *
  2. + *
  3. +	 *    first = { 'a' }
    +	 *    second = null
    +	 *    third = { 'b' }
    +	 *    => result = { ' a', 'b' }
    +	 * 
    + *
  4. + *
  5. +	 *    first = { 'a' }
    +	 *    second = { 'b' }
    +	 *    third = null
    +	 *    => result = { ' a', 'b' }
    +	 * 
    + *
  6. + *
  7. +	 *    first = null
    +	 *    second = null
    +	 *    third = null
    +	 *    => result = null
    +	 * 
    + *
  8. + *
  9. +	 *    first = { 'a' }
    +	 *    second = { 'b' }
    +	 *    third = { 'c' }
    +	 *    => result = { 'a', 'b', 'c' }
    +	 * 
    + *
  10. + *
+ * + * @param first the first array to concatenate + * @param second the second array to concatenate + * @param third the third array to concatenate + * + * @return the concatenation of the three arrays, or null if the three arrays are null. + */ + public static final char[] concat( + char[] first, + char[] second, + char[] third) { + if (first == null) + return concat(second, third); + if (second == null) + return concat(first, third); + if (third == null) + return concat(first, second); + + int length1 = first.length; + int length2 = second.length; + int length3 = third.length; + char[] result = new char[length1 + length2 + length3]; + System.arraycopy(first, 0, result, 0, length1); + System.arraycopy(second, 0, result, length1, length2); + System.arraycopy(third, 0, result, length1 + length2, length3); + return result; + } + + /** + * Answers the concatenation of the two arrays inserting the separator character between the two arrays. + * It answers null if the two arrays are null. + * If the first array is null, then the second array is returned. + * If the second array is null, then the first array is returned. + *
+ *
+ * For example: + *
    + *
  1. +	 *    first = null
    +	 *    second = { 'a' }
    +	 *    separator = '/'
    +	 *    => result = { ' a' }
    +	 * 
    + *
  2. + *
  3. +	 *    first = { ' a' }
    +	 *    second = null
    +	 *    separator = '/'
    +	 *    => result = { ' a' }
    +	 * 
    + *
  4. + *
  5. +	 *    first = { ' a' }
    +	 *    second = { ' b' }
    +	 *    separator = '/'
    +	 *    => result = { ' a' , '/', 'b' }
    +	 * 
    + *
  6. + *
+ * + * @param first the first array to concatenate + * @param second the second array to concatenate + * @param separator the character to insert + * @return the concatenation of the two arrays inserting the separator character + * between the two arrays , or null if the two arrays are null. + */ + public static final char[] concat( + char[] first, + char[] second, + char separator) { + if (first == null) + return second; + if (second == null) + return first; + + int length1 = first.length; + if (length1 == 0) + return second; + int length2 = second.length; + if (length2 == 0) + return first; + + char[] result = new char[length1 + length2 + 1]; + System.arraycopy(first, 0, result, 0, length1); + result[length1] = separator; + System.arraycopy(second, 0, result, length1 + 1, length2); + return result; + } + + /** + * Answers the concatenation of the three arrays inserting the sep1 character between the + * two arrays and sep2 between the last two. + * It answers null if the three arrays are null. + * If the first array is null, then it answers the concatenation of second and third inserting + * the sep2 character between them. + * If the second array is null, then it answers the concatenation of first and third inserting + * the sep1 character between them. + * If the third array is null, then it answers the concatenation of first and second inserting + * the sep1 character between them. + *
+ *
+ * For example: + *
    + *
  1. +	 *    first = null
    +	 *    sep1 = '/'
    +	 *    second = { 'a' }
    +	 *    sep2 = ':'
    +	 *    third = { 'b' }
    +	 *    => result = { ' a' , ':', 'b' }
    +	 * 
    + *
  2. + *
  3. +	 *    first = { 'a' }
    +	 *    sep1 = '/'
    +	 *    second = null
    +	 *    sep2 = ':'
    +	 *    third = { 'b' }
    +	 *    => result = { ' a' , '/', 'b' }
    +	 * 
    + *
  4. + *
  5. +	 *    first = { 'a' }
    +	 *    sep1 = '/'
    +	 *    second = { 'b' }
    +	 *    sep2 = ':'
    +	 *    third = null
    +	 *    => result = { ' a' , '/', 'b' }
    +	 * 
    + *
  6. + *
  7. +	 *    first = { 'a' }
    +	 *    sep1 = '/'
    +	 *    second = { 'b' }
    +	 *    sep2 = ':'
    +	 *    third = { 'c' }
    +	 *    => result = { ' a' , '/', 'b' , ':', 'c' }
    +	 * 
    + *
  8. + *
+ * + * @param first the first array to concatenate + * @param sep1 the character to insert + * @param second the second array to concatenate + * @param sep2 the character to insert + * @param third the second array to concatenate + * @return the concatenation of the three arrays inserting the sep1 character between the + * two arrays and sep2 between the last two. + */ + public static final char[] concat( + char[] first, + char sep1, + char[] second, + char sep2, + char[] third) { + if (first == null) + return concat(second, third, sep2); + if (second == null) + return concat(first, third, sep1); + if (third == null) + return concat(first, second, sep1); + + int length1 = first.length; + int length2 = second.length; + int length3 = third.length; + char[] result = new char[length1 + length2 + length3 + 2]; + System.arraycopy(first, 0, result, 0, length1); + result[length1] = sep1; + System.arraycopy(second, 0, result, length1 + 1, length2); + result[length1 + length2 + 1] = sep2; + System.arraycopy(third, 0, result, length1 + length2 + 2, length3); + return result; + } + + /** + * Answers a new array with prepending the prefix character and appending the suffix + * character at the end of the array. If array is null, it answers a new array containing the + * prefix and the suffix characters. + *
+ *
+ * For example:
+ *
    + *
  1. +	 *    prefix = 'a'
    +	 *    array = { 'b' }
    +	 *    suffix = 'c'
    +	 *    => result = { 'a', 'b' , 'c' }
    +	 * 
    + *
  2. + *
  3. +	 *    prefix = 'a'
    +	 *    array = null
    +	 *    suffix = 'c'
    +	 *    => result = { 'a', 'c' }
    +	 * 
  4. + *
+ * + * @param prefix the prefix character + * @param array the array that is concanated with the prefix and suffix characters + * @param suffix the suffix character + * @return the new array + */ + public static final char[] concat(char prefix, char[] array, char suffix) { + if (array == null) + return new char[] { prefix, suffix }; + + int length = array.length; + char[] result = new char[length + 2]; + result[0] = prefix; + System.arraycopy(array, 0, result, 1, length); + result[length + 1] = suffix; + return result; + } + + /** + * Answers the concatenation of the given array parts using the given separator between each + * part and appending the given name at the end. + *
+ *
+ * For example:
+ *
    + *
  1. +	 *    name = { 'c' }
    +	 *    array = { { 'a' }, { 'b' } }
    +	 *    separator = '.'
    +	 *    => result = { 'a', '.', 'b' , '.', 'c' }
    +	 * 
    + *
  2. + *
  3. +	 *    name = null
    +	 *    array = { { 'a' }, { 'b' } }
    +	 *    separator = '.'
    +	 *    => result = { 'a', '.', 'b' }
    +	 * 
  4. + *
  5. +	 *    name = { ' c' }
    +	 *    array = null
    +	 *    separator = '.'
    +	 *    => result = { 'c' }
    +	 * 
  6. + *
+ * + * @param name the given name + * @param array the given array + * @param separator the given separator + * @return the concatenation of the given array parts using the given separator between each + * part and appending the given name at the end + */ + public static final char[] concatWith( + char[] name, + char[][] array, + char separator) { + int nameLength = name == null ? 0 : name.length; + if (nameLength == 0) + return concatWith(array, separator); + + int length = array == null ? 0 : array.length; + if (length == 0) + return name; + + int size = nameLength; + int index = length; + while (--index >= 0) + if (array[index].length > 0) + size += array[index].length + 1; + char[] result = new char[size]; + index = size; + for (int i = length - 1; i >= 0; i--) { + int subLength = array[i].length; + if (subLength > 0) { + index -= subLength; + System.arraycopy(array[i], 0, result, index, subLength); + result[--index] = separator; + } + } + System.arraycopy(name, 0, result, 0, nameLength); + return result; + } + + /** + * Answers the concatenation of the given array parts using the given separator between each + * part and appending the given name at the end. + *
+ *
+ * For example:
+ *
    + *
  1. +	 *    name = { 'c' }
    +	 *    array = { { 'a' }, { 'b' } }
    +	 *    separator = '.'
    +	 *    => result = { 'a', '.', 'b' , '.', 'c' }
    +	 * 
    + *
  2. + *
  3. +	 *    name = null
    +	 *    array = { { 'a' }, { 'b' } }
    +	 *    separator = '.'
    +	 *    => result = { 'a', '.', 'b' }
    +	 * 
  4. + *
  5. +	 *    name = { ' c' }
    +	 *    array = null
    +	 *    separator = '.'
    +	 *    => result = { 'c' }
    +	 * 
  6. + *
+ * + * @param array the given array + * @param name the given name + * @param separator the given separator + * @return the concatenation of the given array parts using the given separator between each + * part and appending the given name at the end + */ + public static final char[] concatWith( + char[][] array, + char[] name, + char separator) { + int nameLength = name == null ? 0 : name.length; + if (nameLength == 0) + return concatWith(array, separator); + + int length = array == null ? 0 : array.length; + if (length == 0) + return name; + + int size = nameLength; + int index = length; + while (--index >= 0) + if (array[index].length > 0) + size += array[index].length + 1; + char[] result = new char[size]; + index = 0; + for (int i = 0; i < length; i++) { + int subLength = array[i].length; + if (subLength > 0) { + System.arraycopy(array[i], 0, result, index, subLength); + index += subLength; + result[index++] = separator; + } + } + System.arraycopy(name, 0, result, index, nameLength); + return result; + } + + /** + * Answers the concatenation of the given array parts using the given separator between each part. + *
+ *
+ * For example:
+ *
    + *
  1. +	 *    array = { { 'a' }, { 'b' } }
    +	 *    separator = '.'
    +	 *    => result = { 'a', '.', 'b' }
    +	 * 
    + *
  2. + *
  3. +	 *    array = null
    +	 *    separator = '.'
    +	 *    => result = { }
    +	 * 
  4. + *
+ * + * @param array the given array + * @param separator the given separator + * @return the concatenation of the given array parts using the given separator between each part + */ + public static final char[] concatWith(char[][] array, char separator) { + int length = array == null ? 0 : array.length; + if (length == 0) + return CharOperation.NO_CHAR; + + int size = length - 1; + int index = length; + while (--index >= 0) { + if (array[index].length == 0) + size--; + else + size += array[index].length; + } + if (size <= 0) + return CharOperation.NO_CHAR; + char[] result = new char[size]; + index = length; + while (--index >= 0) { + length = array[index].length; + if (length > 0) { + System.arraycopy( + array[index], + 0, + result, + (size -= length), + length); + if (--size >= 0) + result[size] = separator; + } + } + return result; + } + + /** + * Answers true if the array contains an occurrence of character, false otherwise. + * + *
+ *
+ * For example: + *
    + *
  1. +	 *    character = 'c'
    +	 *    array = { { ' a' }, { ' b' } }
    +	 *    result => false
    +	 * 
    + *
  2. + *
  3. +	 *    character = 'a'
    +	 *    array = { { ' a' }, { ' b' } }
    +	 *    result => true
    +	 * 
    + *
  4. + *
+ * + * @param character the character to search + * @param array the array in which the search is done + * @return true if the array contains an occurrence of character, false otherwise. + * @throws NullPointerException if array is null. + */ + public static final boolean contains(char character, char[][] array) { + for (int i = array.length; --i >= 0;) { + char[] subarray = array[i]; + for (int j = subarray.length; --j >= 0;) + if (subarray[j] == character) + return true; + } + return false; + } + + /** + * Answers true if the array contains an occurrence of character, false otherwise. + * + *
+ *
+ * For example: + *
    + *
  1. +	 *    character = 'c'
    +	 *    array = { ' b'  }
    +	 *    result => false
    +	 * 
    + *
  2. + *
  3. +	 *    character = 'a'
    +	 *    array = { ' a' , ' b' }
    +	 *    result => true
    +	 * 
    + *
  4. + *
+ * + * @param character the character to search + * @param array the array in which the search is done + * @return true if the array contains an occurrence of character, false otherwise. + * @throws NullPointerException if array is null. + */ + public static final boolean contains(char character, char[] array) { + for (int i = array.length; --i >= 0;) + if (array[i] == character) + return true; + return false; + } + + /** + * Answers a deep copy of the toCopy array. + * + * @param toCopy the array to copy + * @return a deep copy of the toCopy array. + */ + public static final char[][] deepCopy(char[][] toCopy) { + int toCopyLength = toCopy.length; + char[][] result = new char[toCopyLength][]; + for (int i = 0; i < toCopyLength; i++) { + char[] toElement = toCopy[i]; + int toElementLength = toElement.length; + char[] resultElement = new char[toElementLength]; + System.arraycopy(toElement, 0, resultElement, 0, toElementLength); + result[i] = resultElement; + } + return result; + } + + /** + * Return true if array ends with the sequence of characters contained in toBeFound, + * otherwise false. + *
+ *
+ * For example: + *
    + *
  1. +	 *    array = { 'a', 'b', 'c', 'd' }
    +	 *    toBeFound = { 'b', 'c' }
    +	 *    result => false
    +	 * 
    + *
  2. + *
  3. +	 *    array = { 'a', 'b', 'c' }
    +	 *    toBeFound = { 'b', 'c' }
    +	 *    result => true
    +	 * 
    + *
  4. + *
+ * + * @param array the array to check + * @param toBeFound the array to find + * @return true if array ends with the sequence of characters contained in toBeFound, + * otherwise false. + * @throws NullPointerException if array is null or toBeFound is null + */ + public static final boolean endsWith(char[] array, char[] toBeFound) { + int i = toBeFound.length; + int j = array.length - i; + + if (j < 0) + return false; + while (--i >= 0) + if (toBeFound[i] != array[i + j]) + return false; + return true; + } + + /** + * Answers true if the two arrays are identical character by character, otherwise false. + * The equality is case sensitive. + *
+ *
+ * For example: + *
    + *
  1. +	 *    first = null
    +	 *    second = null
    +	 *    result => true
    +	 * 
    + *
  2. + *
  3. +	 *    first = { { } }
    +	 *    second = null
    +	 *    result => false
    +	 * 
    + *
  4. + *
  5. +	 *    first = { { 'a' } }
    +	 *    second = { { 'a' } }
    +	 *    result => true
    +	 * 
    + *
  6. + *
  7. +	 *    first = { { 'A' } }
    +	 *    second = { { 'a' } }
    +	 *    result => false
    +	 * 
    + *
  8. + *
+ * @param first the first array + * @param second the second array + * @return true if the two arrays are identical character by character, otherwise false + */ + public static final boolean equals(char[][] first, char[][] second) { + if (first == second) + return true; + if (first == null || second == null) + return false; + if (first.length != second.length) + return false; + + for (int i = first.length; --i >= 0;) + if (!equals(first[i], second[i])) + return false; + return true; + } + + /** + * If isCaseSensite is true, answers true if the two arrays are identical character + * by character, otherwise false. + * If it is false, answers true if the two arrays are identical character by + * character without checking the case, otherwise false. + *
+ *
+ * For example: + *
    + *
  1. +	 *    first = null
    +	 *    second = null
    +	 *    isCaseSensitive = true
    +	 *    result => true
    +	 * 
    + *
  2. + *
  3. +	 *    first = { { } }
    +	 *    second = null
    +	 *    isCaseSensitive = true
    +	 *    result => false
    +	 * 
    + *
  4. + *
  5. +	 *    first = { { 'A' } }
    +	 *    second = { { 'a' } }
    +	 *    isCaseSensitive = true
    +	 *    result => false
    +	 * 
    + *
  6. + *
  7. +	 *    first = { { 'A' } }
    +	 *    second = { { 'a' } }
    +	 *    isCaseSensitive = false
    +	 *    result => true
    +	 * 
    + *
  8. + *
+ * + * @param first the first array + * @param second the second array + * @param isCaseSensitive check whether or not the equality should be case sensitive + * @return true if the two arrays are identical character by character according to the value + * of isCaseSensitive, otherwise false + */ + public static final boolean equals( + char[][] first, + char[][] second, + boolean isCaseSensitive) { + + if (isCaseSensitive) { + return equals(first, second); + } + if (first == second) + return true; + if (first == null || second == null) + return false; + if (first.length != second.length) + return false; + + for (int i = first.length; --i >= 0;) + if (!equals(first[i], second[i], false)) + return false; + return true; + } + + /** + * Answers true if the two arrays are identical character by character, otherwise false. + * The equality is case sensitive. + *
+ *
+ * For example: + *
    + *
  1. +	 *    first = null
    +	 *    second = null
    +	 *    result => true
    +	 * 
    + *
  2. + *
  3. +	 *    first = { }
    +	 *    second = null
    +	 *    result => false
    +	 * 
    + *
  4. + *
  5. +	 *    first = { 'a' }
    +	 *    second = { 'a' }
    +	 *    result => true
    +	 * 
    + *
  6. + *
  7. +	 *    first = { 'a' }
    +	 *    second = { 'A' }
    +	 *    result => false
    +	 * 
    + *
  8. + *
+ * @param first the first array + * @param second the second array + * @return true if the two arrays are identical character by character, otherwise false + */ + public static final boolean equals(char[] first, char[] second) { + if (first == second) + return true; + if (first == null || second == null) + return false; + if (first.length != second.length) + return false; + + for (int i = first.length; --i >= 0;) + if (first[i] != second[i]) + return false; + return true; + } + + /** + * Answers true if the first array is identical character by character to a portion of the second array + * delimited from position secondStart (inclusive) to secondEnd(exclusive), otherwise false. + * The equality is case sensitive. + *
+ *
+ * For example: + *
    + *
  1. +	 *    first = null
    +	 *    second = null
    +	 *    secondStart = 0
    +	 *    secondEnd = 0
    +	 *    result => true
    +	 * 
    + *
  2. + *
  3. +	 *    first = { }
    +	 *    second = null
    +	 *    secondStart = 0
    +	 *    secondEnd = 0
    +	 *    result => false
    +	 * 
    + *
  4. + *
  5. +	 *    first = { 'a' }
    +	 *    second = { 'a' }
    +	 *    secondStart = 0
    +	 *    secondEnd = 1
    +	 *    result => true
    +	 * 
    + *
  6. + *
  7. +	 *    first = { 'a' }
    +	 *    second = { 'A' }
    +	 *    secondStart = 0
    +	 *    secondEnd = 1
    +	 *    result => false
    +	 * 
    + *
  8. + *
+ * @param first the first array + * @param second the second array + * @param secondStart inclusive start position in the second array to compare + * @param secondEnd exclusive end position in the second array to compare + * @return true if the first array is identical character by character to fragment of second array ranging from secondStart to secondEnd-1, otherwise false + * @since 3.0 + */ + public static final boolean equals(char[] first, char[] second, int secondStart, int secondEnd) { + if (first == second) + return true; + if (first == null || second == null) + return false; + if (first.length != secondEnd - secondStart) + return false; + + for (int i = first.length; --i >= 0;) + if (first[i] != second[i+secondStart]) + return false; + return true; + } + + /** + * If isCaseSensite is true, answers true if the two arrays are identical character + * by character, otherwise false. + * If it is false, answers true if the two arrays are identical character by + * character without checking the case, otherwise false. + *
+ *
+ * For example: + *
    + *
  1. +	 *    first = null
    +	 *    second = null
    +	 *    isCaseSensitive = true
    +	 *    result => true
    +	 * 
    + *
  2. + *
  3. +	 *    first = { }
    +	 *    second = null
    +	 *    isCaseSensitive = true
    +	 *    result => false
    +	 * 
    + *
  4. + *
  5. +	 *    first = { 'A' }
    +	 *    second = { 'a' }
    +	 *    isCaseSensitive = true
    +	 *    result => false
    +	 * 
    + *
  6. + *
  7. +	 *    first = { 'A' }
    +	 *    second = { 'a' }
    +	 *    isCaseSensitive = false
    +	 *    result => true
    +	 * 
    + *
  8. + *
+ * + * @param first the first array + * @param second the second array + * @param isCaseSensitive check whether or not the equality should be case sensitive + * @return true if the two arrays are identical character by character according to the value + * of isCaseSensitive, otherwise false + */ + public static final boolean equals( + char[] first, + char[] second, + boolean isCaseSensitive) { + + if (isCaseSensitive) { + return equals(first, second); + } + if (first == second) + return true; + if (first == null || second == null) + return false; + if (first.length != second.length) + return false; + + for (int i = first.length; --i >= 0;) + if (Character.toLowerCase(first[i]) + != Character.toLowerCase(second[i])) + return false; + return true; + } + /** + * If isCaseSensite is true, the equality is case sensitive, otherwise it is case insensitive. + * + * Answers true if the name contains the fragment at the starting index startIndex, otherwise false. + *
+ *
+ * For example: + *
    + *
  1. +	 *    fragment = { 'b', 'c' , 'd' }
    +	 *    name = { 'a', 'b', 'c' , 'd' }
    +	 *    startIndex = 1
    +	 *    isCaseSensitive = true
    +	 *    result => true
    +	 * 
    + *
  2. + *
  3. +	 *    fragment = { 'b', 'c' , 'd' }
    +	 *    name = { 'a', 'b', 'C' , 'd' }
    +	 *    startIndex = 1
    +	 *    isCaseSensitive = true
    +	 *    result => false
    +	 * 
    + *
  4. + *
  5. +	 *    fragment = { 'b', 'c' , 'd' }
    +	 *    name = { 'a', 'b', 'C' , 'd' }
    +	 *    startIndex = 0
    +	 *    isCaseSensitive = false
    +	 *    result => false
    +	 * 
    + *
  6. + *
  7. +	 *    fragment = { 'b', 'c' , 'd' }
    +	 *    name = { 'a', 'b'}
    +	 *    startIndex = 0
    +	 *    isCaseSensitive = true
    +	 *    result => false
    +	 * 
    + *
  8. + *
+ * + * @param fragment the fragment to check + * @param name the array to check + * @param startIndex the starting index + * @param isCaseSensitive check whether or not the equality should be case sensitive + * @return true if the name contains the fragment at the starting index startIndex according to the + * value of isCaseSensitive, otherwise false. + * @throws NullPointerException if fragment or name is null. + */ + public static final boolean fragmentEquals( + char[] fragment, + char[] name, + int startIndex, + boolean isCaseSensitive) { + + int max = fragment.length; + if (name.length < max + startIndex) + return false; + if (isCaseSensitive) { + for (int i = max; + --i >= 0; + ) // assumes the prefix is not larger than the name + if (fragment[i] != name[i + startIndex]) + return false; + return true; + } + for (int i = max; + --i >= 0; + ) // assumes the prefix is not larger than the name + if (Character.toLowerCase(fragment[i]) + != Character.toLowerCase(name[i + startIndex])) + return false; + return true; + } + + /** + * Answers a hashcode for the array + * + * @param array the array for which a hashcode is required + * @return the hashcode + * @throws NullPointerException if array is null + */ + public static final int hashCode(char[] array) { + int hash = 0; + int offset = 0; + int length = array.length; + if (length < 16) { + for (int i = length; i > 0; i--) + hash = (hash * 37) + array[offset++]; + } else { + // only sample some characters + int skip = length / 8; + for (int i = length; i > 0; i -= skip, offset += skip) + hash = (hash * 39) + array[offset]; + } + return hash & 0x7FFFFFFF; + } + /** + * Answers true if c is a whitespace according to the JLS (\u000a, \u000c, \u000d, \u0009), otherwise false. + *
+ *
+ * For example: + *
    + *
  1. +	 *    c = ' '
    +	 *    result => true
    +	 * 
    + *
  2. + *
  3. +	 *    c = '\u3000'
    +	 *    result => false
    +	 * 
    + *
  4. + *
+ * + * @param c the character to check + * @return true if c is a whitespace according to the JLS, otherwise false. + */ + public static boolean isWhitespace(char c) { + switch (c) { + case 10 : /* \ u000a: LINE FEED */ + case 12 : /* \ u000c: FORM FEED */ + case 13 : /* \ u000d: CARRIAGE RETURN */ + case 32 : /* \ u0020: SPACE */ + case 9 : /* \ u0009: HORIZONTAL TABULATION */ + return true; + default : + return false; + } + } + + /** + * Answers the first index in the array for which the corresponding character is + * equal to toBeFound. Answers -1 if no occurrence of this character is found. + *
+ *
+ * For example: + *
    + *
  1. +	 *    toBeFound = 'c'
    +	 *    array = { ' a', 'b', 'c', 'd' }
    +	 *    result => 2
    +	 * 
    + *
  2. + *
  3. +	 *    toBeFound = 'e'
    +	 *    array = { ' a', 'b', 'c', 'd' }
    +	 *    result => -1
    +	 * 
    + *
  4. + *
+ * + * @param toBeFound the character to search + * @param array the array to be searched + * @return the first index in the array for which the corresponding character is + * equal to toBeFound, -1 otherwise + * @throws NullPointerException if array is null + */ + public static final int indexOf(char toBeFound, char[] array) { + for (int i = 0; i < array.length; i++) + if (toBeFound == array[i]) + return i; + return -1; + } + + /** + * Answers the first index in the array for which the corresponding character is + * equal to toBeFound starting the search at index start. + * Answers -1 if no occurrence of this character is found. + *
+ *
+ * For example: + *
    + *
  1. +	 *    toBeFound = 'c'
    +	 *    array = { ' a', 'b', 'c', 'd' }
    +	 *    start = 2
    +	 *    result => 2
    +	 * 
    + *
  2. + *
  3. +	 *    toBeFound = 'c'
    +	 *    array = { ' a', 'b', 'c', 'd' }
    +	 *    start = 3
    +	 *    result => -1
    +	 * 
    + *
  4. + *
  5. +	 *    toBeFound = 'e'
    +	 *    array = { ' a', 'b', 'c', 'd' }
    +	 *    start = 1
    +	 *    result => -1
    +	 * 
    + *
  6. + *
+ * + * @param toBeFound the character to search + * @param array the array to be searched + * @param start the starting index + * @return the first index in the array for which the corresponding character is + * equal to toBeFound, -1 otherwise + * @throws NullPointerException if array is null + * @throws ArrayIndexOutOfBoundsException if start is lower than 0 + */ + public static final int indexOf(char toBeFound, char[] array, int start) { + for (int i = start; i < array.length; i++) + if (toBeFound == array[i]) + return i; + return -1; + } + + /** + * Answers the last index in the array for which the corresponding character is + * equal to toBeFound starting from the end of the array. + * Answers -1 if no occurrence of this character is found. + *
+ *
+ * For example: + *
    + *
  1. +	 *    toBeFound = 'c'
    +	 *    array = { ' a', 'b', 'c', 'd' , 'c', 'e' }
    +	 *    result => 4
    +	 * 
    + *
  2. + *
  3. +	 *    toBeFound = 'e'
    +	 *    array = { ' a', 'b', 'c', 'd' }
    +	 *    result => -1
    +	 * 
    + *
  4. + *
+ * + * @param toBeFound the character to search + * @param array the array to be searched + * @return the last index in the array for which the corresponding character is + * equal to toBeFound starting from the end of the array, -1 otherwise + * @throws NullPointerException if array is null + */ + public static final int lastIndexOf(char toBeFound, char[] array) { + for (int i = array.length; --i >= 0;) + if (toBeFound == array[i]) + return i; + return -1; + } + + /** + * Answers the last index in the array for which the corresponding character is + * equal to toBeFound stopping at the index startIndex. + * Answers -1 if no occurrence of this character is found. + *
+ *
+ * For example: + *
    + *
  1. +	 *    toBeFound = 'c'
    +	 *    array = { ' a', 'b', 'c', 'd' }
    +	 *    startIndex = 2
    +	 *    result => 2
    +	 * 
    + *
  2. + *
  3. +	 *    toBeFound = 'c'
    +	 *    array = { ' a', 'b', 'c', 'd', 'e' }
    +	 *    startIndex = 3
    +	 *    result => -1
    +	 * 
    + *
  4. + *
  5. +	 *    toBeFound = 'e'
    +	 *    array = { ' a', 'b', 'c', 'd' }
    +	 *    startIndex = 0
    +	 *    result => -1
    +	 * 
    + *
  6. + *
+ * + * @param toBeFound the character to search + * @param array the array to be searched + * @param startIndex the stopping index + * @return the last index in the array for which the corresponding character is + * equal to toBeFound stopping at the index startIndex, -1 otherwise + * @throws NullPointerException if array is null + * @throws ArrayIndexOutOfBoundsException if startIndex is lower than 0 + */ + public static final int lastIndexOf( + char toBeFound, + char[] array, + int startIndex) { + for (int i = array.length; --i >= startIndex;) + if (toBeFound == array[i]) + return i; + return -1; + } + + /** + * Answers the last index in the array for which the corresponding character is + * equal to toBeFound starting from endIndex to startIndex. + * Answers -1 if no occurrence of this character is found. + *
+ *
+ * For example: + *
    + *
  1. +	 *    toBeFound = 'c'
    +	 *    array = { ' a', 'b', 'c', 'd' }
    +	 *    startIndex = 2
    +	 *    endIndex = 2
    +	 *    result => 2
    +	 * 
    + *
  2. + *
  3. +	 *    toBeFound = 'c'
    +	 *    array = { ' a', 'b', 'c', 'd', 'e' }
    +	 *    startIndex = 3
    +	 *    endIndex = 4
    +	 *    result => -1
    +	 * 
    + *
  4. + *
  5. +	 *    toBeFound = 'e'
    +	 *    array = { ' a', 'b', 'c', 'd' }
    +	 *    startIndex = 0
    +	 *    endIndex = 3
    +	 *    result => -1
    +	 * 
    + *
  6. + *
+ * + * @param toBeFound the character to search + * @param array the array to be searched + * @param startIndex the stopping index + * @param endIndex the starting index + * @return the last index in the array for which the corresponding character is + * equal to toBeFound starting from endIndex to startIndex, -1 otherwise + * @throws NullPointerException if array is null + * @throws ArrayIndexOutOfBoundsException if endIndex is greater or equals to array length or starting is lower than 0 + */ + public static final int lastIndexOf( + char toBeFound, + char[] array, + int startIndex, + int endIndex) { + for (int i = endIndex; --i >= startIndex;) + if (toBeFound == array[i]) + return i; + return -1; + } + + /** + * Answers the last portion of a name given a separator. + *
+ *
+ * For example, + *
+	 * 	lastSegment("java.lang.Object".toCharArray(),'.') --> Object
+	 * 
+ * + * @param array the array + * @param separator the given separator + * @return the last portion of a name given a separator + * @throws NullPointerException if array is null + */ + final static public char[] lastSegment(char[] array, char separator) { + int pos = lastIndexOf(separator, array); + if (pos < 0) + return array; + return subarray(array, pos + 1, array.length); + } + + /** + * Answers true if the pattern matches the given name, false otherwise. This char[] pattern matching + * accepts wild-cards '*' and '?'. + * + * When not case sensitive, the pattern is assumed to already be lowercased, the + * name will be lowercased character per character as comparing. + * If name is null, the answer is false. + * If pattern is null, the answer is true if name is not null. + *
+ *
+ * For example: + *
    + *
  1. +	 *    pattern = { '?', 'b', '*' }
    +	 *    name = { 'a', 'b', 'c' , 'd' }
    +	 *    isCaseSensitive = true
    +	 *    result => true
    +	 * 
    + *
  2. + *
  3. +	 *    pattern = { '?', 'b', '?' }
    +	 *    name = { 'a', 'b', 'c' , 'd' }
    +	 *    isCaseSensitive = true
    +	 *    result => false
    +	 * 
    + *
  4. + *
  5. +	 *    pattern = { 'b', '*' }
    +	 *    name = { 'a', 'b', 'c' , 'd' }
    +	 *    isCaseSensitive = true
    +	 *    result => false
    +	 * 
    + *
  6. + *
+ * + * @param pattern the given pattern + * @param name the given name + * @param isCaseSensitive flag to know whether or not the matching should be case sensitive + * @return true if the pattern matches the given name, false otherwise + */ + public static final boolean match( + char[] pattern, + char[] name, + boolean isCaseSensitive) { + + if (name == null) + return false; // null name cannot match + if (pattern == null) + return true; // null pattern is equivalent to '*' + + return match( + pattern, + 0, + pattern.length, + name, + 0, + name.length, + isCaseSensitive); + } + + /** + * Answers true if the a sub-pattern matches the subpart of the given name, false otherwise. + * char[] pattern matching, accepting wild-cards '*' and '?'. Can match only subset of name/pattern. + * end positions are non-inclusive. + * The subpattern is defined by the patternStart and pattternEnd positions. + * When not case sensitive, the pattern is assumed to already be lowercased, the + * name will be lowercased character per character as comparing. + *
+ *
+ * For example: + *
    + *
  1. +	 *    pattern = { '?', 'b', '*' }
    +	 *    patternStart = 1
    +	 *    patternEnd = 3
    +	 *    name = { 'a', 'b', 'c' , 'd' }
    +	 *    nameStart = 1
    +	 *    nameEnd = 4
    +	 *    isCaseSensitive = true
    +	 *    result => true
    +	 * 
    + *
  2. + *
  3. +	 *    pattern = { '?', 'b', '*' }
    +	 *    patternStart = 1
    +	 *    patternEnd = 2
    +	 *    name = { 'a', 'b', 'c' , 'd' }
    +	 *    nameStart = 1
    +	 *    nameEnd = 2
    +	 *    isCaseSensitive = true
    +	 *    result => false
    +	 * 
    + *
  4. + *
+ * + * @param pattern the given pattern + * @param patternStart the given pattern start + * @param patternEnd the given pattern end + * @param name the given name + * @param nameStart the given name start + * @param nameEnd the given name end + * @param isCaseSensitive flag to know if the matching should be case sensitive + * @return true if the a sub-pattern matches the subpart of the given name, false otherwise + */ + public static final boolean match( + char[] pattern, + int patternStart, + int patternEnd, + char[] name, + int nameStart, + int nameEnd, + boolean isCaseSensitive) { + + if (name == null) + return false; // null name cannot match + if (pattern == null) + return true; // null pattern is equivalent to '*' + int iPattern = patternStart; + int iName = nameStart; + + if (patternEnd < 0) + patternEnd = pattern.length; + if (nameEnd < 0) + nameEnd = name.length; + + /* check first segment */ + char patternChar = 0; + while ((iPattern < patternEnd) + && (patternChar = pattern[iPattern]) != '*') { + if (iName == nameEnd) + return false; + if (patternChar + != (isCaseSensitive + ? name[iName] + : Character.toLowerCase(name[iName])) + && patternChar != '?') { + return false; + } + iName++; + iPattern++; + } + /* check sequence of star+segment */ + int segmentStart; + if (patternChar == '*') { + segmentStart = ++iPattern; // skip star + } else { + segmentStart = 0; // force iName check + } + int prefixStart = iName; + checkSegment : while (iName < nameEnd) { + if (iPattern == patternEnd) { + iPattern = segmentStart; // mismatch - restart current segment + iName = ++prefixStart; + continue checkSegment; + } + /* segment is ending */ + if ((patternChar = pattern[iPattern]) == '*') { + segmentStart = ++iPattern; // skip start + if (segmentStart == patternEnd) { + return true; + } + prefixStart = iName; + continue checkSegment; + } + /* check current name character */ + if ((isCaseSensitive ? name[iName] : Character.toLowerCase(name[iName])) + != patternChar + && patternChar != '?') { + iPattern = segmentStart; // mismatch - restart current segment + iName = ++prefixStart; + continue checkSegment; + } + iName++; + iPattern++; + } + + return (segmentStart == patternEnd) + || (iName == nameEnd && iPattern == patternEnd) + || (iPattern == patternEnd - 1 && pattern[iPattern] == '*'); + } + + /** + * Answers true if the pattern matches the filepath using the pathSepatator, false otherwise. + * + * Path char[] pattern matching, accepting wild-cards '**', '*' and '?' (using Ant directory tasks + * conventions, also see "http://jakarta.apache.org/ant/manual/dirtasks.html#defaultexcludes"). + * Path pattern matching is enhancing regular pattern matching in supporting extra rule where '**' represent + * any folder combination. + * Special rule: + * - foo\ is equivalent to foo\** + * When not case sensitive, the pattern is assumed to already be lowercased, the + * name will be lowercased character per character as comparing. + * + * @param pattern the given pattern + * @param filepath the given path + * @param isCaseSensitive to find out whether or not the matching should be case sensitive + * @param pathSeparator the given path separator + * @return true if the pattern matches the filepath using the pathSepatator, false otherwise + */ + public static final boolean pathMatch( + char[] pattern, + char[] filepath, + boolean isCaseSensitive, + char pathSeparator) { + + if (filepath == null) + return false; // null name cannot match + if (pattern == null) + return true; // null pattern is equivalent to '*' + + // offsets inside pattern + int pSegmentStart = pattern[0] == pathSeparator ? 1 : 0; + int pLength = pattern.length; + int pSegmentEnd = CharOperation.indexOf(pathSeparator, pattern, pSegmentStart+1); + if (pSegmentEnd < 0) pSegmentEnd = pLength; + + // special case: pattern foo\ is equivalent to foo\** + boolean freeTrailingDoubleStar = pattern[pLength - 1] == pathSeparator; + + // offsets inside filepath + int fSegmentStart, fLength = filepath.length; + if (filepath[0] != pathSeparator){ + fSegmentStart = 0; + } else { + fSegmentStart = 1; + } + if (fSegmentStart != pSegmentStart) { + return false; // both must start with a separator or none. + } + int fSegmentEnd = CharOperation.indexOf(pathSeparator, filepath, fSegmentStart+1); + if (fSegmentEnd < 0) fSegmentEnd = fLength; + + // first segments + while (pSegmentStart < pLength + && !(pSegmentEnd == pLength && freeTrailingDoubleStar + || (pSegmentEnd == pSegmentStart + 2 + && pattern[pSegmentStart] == '*' + && pattern[pSegmentStart + 1] == '*'))) { + + if (fSegmentStart >= fLength) + return false; + if (!CharOperation + .match( + pattern, + pSegmentStart, + pSegmentEnd, + filepath, + fSegmentStart, + fSegmentEnd, + isCaseSensitive)) { + return false; + } + + // jump to next segment + pSegmentEnd = + CharOperation.indexOf( + pathSeparator, + pattern, + pSegmentStart = pSegmentEnd + 1); + // skip separator + if (pSegmentEnd < 0) + pSegmentEnd = pLength; + + fSegmentEnd = + CharOperation.indexOf( + pathSeparator, + filepath, + fSegmentStart = fSegmentEnd + 1); + // skip separator + if (fSegmentEnd < 0) fSegmentEnd = fLength; + } + + /* check sequence of doubleStar+segment */ + int pSegmentRestart; + if ((pSegmentStart >= pLength && freeTrailingDoubleStar) + || (pSegmentEnd == pSegmentStart + 2 + && pattern[pSegmentStart] == '*' + && pattern[pSegmentStart + 1] == '*')) { + pSegmentEnd = + CharOperation.indexOf( + pathSeparator, + pattern, + pSegmentStart = pSegmentEnd + 1); + // skip separator + if (pSegmentEnd < 0) pSegmentEnd = pLength; + pSegmentRestart = pSegmentStart; + } else { + if (pSegmentStart >= pLength) return fSegmentStart >= fLength; // true if filepath is done too. + pSegmentRestart = 0; // force fSegmentStart check + } + int fSegmentRestart = fSegmentStart; + checkSegment : while (fSegmentStart < fLength) { + + if (pSegmentStart >= pLength) { + if (freeTrailingDoubleStar) return true; + // mismatch - restart current path segment + pSegmentEnd = + CharOperation.indexOf(pathSeparator, pattern, pSegmentStart = pSegmentRestart); + if (pSegmentEnd < 0) pSegmentEnd = pLength; + + fSegmentRestart = + CharOperation.indexOf(pathSeparator, filepath, fSegmentRestart + 1); + // skip separator + if (fSegmentRestart < 0) { + fSegmentRestart = fLength; + } else { + fSegmentRestart++; + } + fSegmentEnd = + CharOperation.indexOf(pathSeparator, filepath, fSegmentStart = fSegmentRestart); + if (fSegmentEnd < 0) fSegmentEnd = fLength; + continue checkSegment; + } + + /* path segment is ending */ + if (pSegmentEnd == pSegmentStart + 2 + && pattern[pSegmentStart] == '*' + && pattern[pSegmentStart + 1] == '*') { + pSegmentEnd = + CharOperation.indexOf(pathSeparator, pattern, pSegmentStart = pSegmentEnd + 1); + // skip separator + if (pSegmentEnd < 0) pSegmentEnd = pLength; + pSegmentRestart = pSegmentStart; + fSegmentRestart = fSegmentStart; + if (pSegmentStart >= pLength) return true; + continue checkSegment; + } + /* chech current path segment */ + if (!CharOperation.match( + pattern, + pSegmentStart, + pSegmentEnd, + filepath, + fSegmentStart, + fSegmentEnd, + isCaseSensitive)) { + // mismatch - restart current path segment + pSegmentEnd = + CharOperation.indexOf(pathSeparator, pattern, pSegmentStart = pSegmentRestart); + if (pSegmentEnd < 0) pSegmentEnd = pLength; + + fSegmentRestart = + CharOperation.indexOf(pathSeparator, filepath, fSegmentRestart + 1); + // skip separator + if (fSegmentRestart < 0) { + fSegmentRestart = fLength; + } else { + fSegmentRestart++; + } + fSegmentEnd = + CharOperation.indexOf(pathSeparator, filepath, fSegmentStart = fSegmentRestart); + if (fSegmentEnd < 0) fSegmentEnd = fLength; + continue checkSegment; + } + // jump to next segment + pSegmentEnd = + CharOperation.indexOf( + pathSeparator, + pattern, + pSegmentStart = pSegmentEnd + 1); + // skip separator + if (pSegmentEnd < 0) + pSegmentEnd = pLength; + + fSegmentEnd = + CharOperation.indexOf( + pathSeparator, + filepath, + fSegmentStart = fSegmentEnd + 1); + // skip separator + if (fSegmentEnd < 0) + fSegmentEnd = fLength; + } + + return (pSegmentRestart >= pSegmentEnd) + || (fSegmentStart >= fLength && pSegmentStart >= pLength) + || (pSegmentStart == pLength - 2 + && pattern[pSegmentStart] == '*' + && pattern[pSegmentStart + 1] == '*') + || (pSegmentStart == pLength && freeTrailingDoubleStar); + } + + /** + * Answers the number of occurrences of the given character in the given array, 0 if any. + * + *
+ *
+ * For example: + *
    + *
  1. +	 *    toBeFound = 'b'
    +	 *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 *    result => 3
    +	 * 
    + *
  2. + *
  3. +	 *    toBeFound = 'c'
    +	 *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 *    result => 0
    +	 * 
    + *
  4. + *
+ * + * @param toBeFound the given character + * @param array the given array + * @return the number of occurrences of the given character in the given array, 0 if any + * @throws NullPointerException if array is null + */ + public static final int occurencesOf(char toBeFound, char[] array) { + int count = 0; + for (int i = 0; i < array.length; i++) + if (toBeFound == array[i]) + count++; + return count; + } + + /** + * Answers the number of occurrences of the given character in the given array starting + * at the given index, 0 if any. + * + *
+ *
+ * For example: + *
    + *
  1. +	 *    toBeFound = 'b'
    +	 *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 *    start = 2
    +	 *    result => 2
    +	 * 
    + *
  2. + *
  3. +	 *    toBeFound = 'c'
    +	 *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 *    start = 0
    +	 *    result => 0
    +	 * 
    + *
  4. + *
+ * + * @param toBeFound the given character + * @param array the given array + * @param start the given index + * @return the number of occurrences of the given character in the given array, 0 if any + * @throws NullPointerException if array is null + * @throws ArrayIndexOutOfBoundsException if start is lower than 0 + */ + public static final int occurencesOf( + char toBeFound, + char[] array, + int start) { + int count = 0; + for (int i = start; i < array.length; i++) + if (toBeFound == array[i]) + count++; + return count; + } + + /** + * Answers true if the given name starts with the given prefix, false otherwise. + * The comparison is case sensitive. + *
+ *
+ * For example: + *
    + *
  1. +	 *    prefix = { 'a' , 'b' }
    +	 *    name = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 *    result => true
    +	 * 
    + *
  2. + *
  3. +	 *    prefix = { 'a' , 'c' }
    +	 *    name = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 *    result => false
    +	 * 
    + *
  4. + *
+ * + * @param prefix the given prefix + * @param name the given name + * @return true if the given name starts with the given prefix, false otherwise + * @throws NullPointerException if the given name is null or if the given prefix is null + */ + public static final boolean prefixEquals(char[] prefix, char[] name) { + + int max = prefix.length; + if (name.length < max) + return false; + for (int i = max; + --i >= 0; + ) // assumes the prefix is not larger than the name + if (prefix[i] != name[i]) + return false; + return true; + } + + /** + * Answers true if the given name starts with the given prefix, false otherwise. + * isCaseSensitive is used to find out whether or not the comparison should be case sensitive. + *
+ *
+ * For example: + *
    + *
  1. +	 *    prefix = { 'a' , 'B' }
    +	 *    name = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 *    isCaseSensitive = false
    +	 *    result => true
    +	 * 
    + *
  2. + *
  3. +	 *    prefix = { 'a' , 'B' }
    +	 *    name = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 *    isCaseSensitive = true
    +	 *    result => false
    +	 * 
    + *
  4. + *
+ * + * @param prefix the given prefix + * @param name the given name + * @param isCaseSensitive to find out whether or not the comparison should be case sensitive + * @return true if the given name starts with the given prefix, false otherwise + * @throws NullPointerException if the given name is null or if the given prefix is null + */ + public static final boolean prefixEquals( + char[] prefix, + char[] name, + boolean isCaseSensitive) { + + int max = prefix.length; + if (name.length < max) + return false; + if (isCaseSensitive) { + for (int i = max; + --i >= 0; + ) // assumes the prefix is not larger than the name + if (prefix[i] != name[i]) + return false; + return true; + } + + for (int i = max; + --i >= 0; + ) // assumes the prefix is not larger than the name + if (Character.toLowerCase(prefix[i]) + != Character.toLowerCase(name[i])) + return false; + return true; + } + + /** + * Replace all occurrence of the character to be replaced with the remplacement character in the + * given array. + *
+ *
+ * For example: + *
    + *
  1. +	 *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 *    toBeReplaced = 'b'
    +	 *    replacementChar = 'a'
    +	 *    result => No returned value, but array is now equals to { 'a' , 'a', 'a', 'a', 'a', 'a' }
    +	 * 
    + *
  2. + *
  3. +	 *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 *    toBeReplaced = 'c'
    +	 *    replacementChar = 'a'
    +	 *    result => No returned value, but array is now equals to { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 * 
    + *
  4. + *
+ * + * @param array the given array + * @param toBeReplaced the character to be replaced + * @param replacementChar the replacement character + * @throws NullPointerException if the given array is null + */ + public static final void replace( + char[] array, + char toBeReplaced, + char replacementChar) { + if (toBeReplaced != replacementChar) { + for (int i = 0, max = array.length; i < max; i++) { + if (array[i] == toBeReplaced) + array[i] = replacementChar; + } + } + } + + /** + * Answers a new array of characters with substitutions. No side-effect is operated on the original + * array, in case no substitution happened, then the result is the same as the + * original one. + *
+ *
+ * For example: + *
    + *
  1. +	 *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 *    toBeReplaced = { 'b' }
    +	 *    replacementChar = { 'a', 'a' }
    +	 *    result => { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }
    +	 * 
    + *
  2. + *
  3. +	 *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 *    toBeReplaced = { 'c' }
    +	 *    replacementChar = { 'a' }
    +	 *    result => { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 * 
    + *
  4. + *
+ * + * @param array the given array + * @param toBeReplaced characters to be replaced + * @param replacementChars the replacement characters + * @return a new array of characters with substitutions or the given array if none + * @throws NullPointerException if the given array is null + */ + public static final char[] replace( + char[] array, + char[] toBeReplaced, + char[] replacementChars) { + + int max = array.length; + int replacedLength = toBeReplaced.length; + int replacementLength = replacementChars.length; + + int[] starts = new int[5]; + int occurrenceCount = 0; + + if (!equals(toBeReplaced, replacementChars)) { + + next : for (int i = 0; i < max; i++) { + int j = 0; + while (j < replacedLength) { + if (i + j == max) + continue next; + if (array[i + j] != toBeReplaced[j++]) + continue next; + } + if (occurrenceCount == starts.length) { + System.arraycopy( + starts, + 0, + starts = new int[occurrenceCount * 2], + 0, + occurrenceCount); + } + starts[occurrenceCount++] = i; + } + } + if (occurrenceCount == 0) + return array; + char[] result = + new char[max + + occurrenceCount * (replacementLength - replacedLength)]; + int inStart = 0, outStart = 0; + for (int i = 0; i < occurrenceCount; i++) { + int offset = starts[i] - inStart; + System.arraycopy(array, inStart, result, outStart, offset); + inStart += offset; + outStart += offset; + System.arraycopy( + replacementChars, + 0, + result, + outStart, + replacementLength); + inStart += replacedLength; + outStart += replacementLength; + } + System.arraycopy(array, inStart, result, outStart, max - inStart); + return result; + } + + /** + * Return a new array which is the split of the given array using the given divider and triming each subarray to remove + * whitespaces equals to ' '. + *
+ *
+ * For example: + *
    + *
  1. +	 *    divider = 'b'
    +	 *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 *    result => { { 'a' }, {  }, { 'a' }, { 'a' } }
    +	 * 
    + *
  2. + *
  3. +	 *    divider = 'c'
    +	 *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 *    result => { { 'a', 'b', 'b', 'a', 'b', 'a' } }
    +	 * 
    + *
  4. + *
  5. +	 *    divider = 'b'
    +	 *    array = { 'a' , ' ', 'b', 'b', 'a', 'b', 'a' }
    +	 *    result => { { 'a' }, {  }, { 'a' }, { 'a' } }
    +	 * 
    + *
  6. + *
  7. +	 *    divider = 'c'
    +	 *    array = { ' ', ' ', 'a' , 'b', 'b', 'a', 'b', 'a', ' ' }
    +	 *    result => { { 'a', 'b', 'b', 'a', 'b', 'a' } }
    +	 * 
    + *
  8. + *
+ * + * @param divider the given divider + * @param array the given array + * @return a new array which is the split of the given array using the given divider and triming each subarray to remove + * whitespaces equals to ' ' + */ + public static final char[][] splitAndTrimOn(char divider, char[] array) { + int length = array == null ? 0 : array.length; + if (length == 0) + return NO_CHAR_CHAR; + + int wordCount = 1; + for (int i = 0; i < length; i++) + if (array[i] == divider) + wordCount++; + char[][] split = new char[wordCount][]; + int last = 0, currentWord = 0; + for (int i = 0; i < length; i++) { + if (array[i] == divider) { + int start = last, end = i - 1; + while (start < i && array[start] == ' ') + start++; + while (end > start && array[end] == ' ') + end--; + split[currentWord] = new char[end - start + 1]; + System.arraycopy( + array, + start, + split[currentWord++], + 0, + end - start + 1); + last = i + 1; + } + } + int start = last, end = length - 1; + while (start < length && array[start] == ' ') + start++; + while (end > start && array[end] == ' ') + end--; + split[currentWord] = new char[end - start + 1]; + System.arraycopy( + array, + start, + split[currentWord++], + 0, + end - start + 1); + return split; + } + + /** + * Return a new array which is the split of the given array using the given divider. + *
+ *
+ * For example: + *
    + *
  1. +	 *    divider = 'b'
    +	 *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 *    result => { { 'a' }, {  }, { 'a' }, { 'a' } }
    +	 * 
    + *
  2. + *
  3. +	 *    divider = 'c'
    +	 *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 *    result => { { 'a', 'b', 'b', 'a', 'b', 'a' } }
    +	 * 
    + *
  4. + *
  5. +	 *    divider = 'c'
    +	 *    array = { ' ', ' ', 'a' , 'b', 'b', 'a', 'b', 'a', ' ' }
    +	 *    result => { { ' ', 'a', 'b', 'b', 'a', 'b', 'a', ' ' } }
    +	 * 
    + *
  6. + *
+ * + * @param divider the given divider + * @param array the given array + * @return a new array which is the split of the given array using the given divider + */ + public static final char[][] splitOn(char divider, char[] array) { + int length = array == null ? 0 : array.length; + if (length == 0) + return NO_CHAR_CHAR; + + int wordCount = 1; + for (int i = 0; i < length; i++) + if (array[i] == divider) + wordCount++; + char[][] split = new char[wordCount][]; + int last = 0, currentWord = 0; + for (int i = 0; i < length; i++) { + if (array[i] == divider) { + split[currentWord] = new char[i - last]; + System.arraycopy( + array, + last, + split[currentWord++], + 0, + i - last); + last = i + 1; + } + } + split[currentWord] = new char[length - last]; + System.arraycopy(array, last, split[currentWord], 0, length - last); + return split; + } + + /** + * Return a new array which is the split of the given array using the given divider. The given end + * is exclusive and the given start is inclusive. + *
+ *
+ * For example: + *
    + *
  1. +	 *    divider = 'b'
    +	 *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 *    start = 2
    +	 *    end = 5
    +	 *    result => { {  }, { 'a' }, {  } }
    +	 * 
    + *
  2. + *
+ * + * @param divider the given divider + * @param array the given array + * @param start the given starting index + * @param end the given ending index + * @return a new array which is the split of the given array using the given divider + * @throws ArrayIndexOutOfBoundsException if start is lower than 0 or end is greater than the array length + */ + public static final char[][] splitOn( + char divider, + char[] array, + int start, + int end) { + int length = array == null ? 0 : array.length; + if (length == 0 || start > end) + return NO_CHAR_CHAR; + + int wordCount = 1; + for (int i = start; i < end; i++) + if (array[i] == divider) + wordCount++; + char[][] split = new char[wordCount][]; + int last = start, currentWord = 0; + for (int i = start; i < end; i++) { + if (array[i] == divider) { + split[currentWord] = new char[i - last]; + System.arraycopy( + array, + last, + split[currentWord++], + 0, + i - last); + last = i + 1; + } + } + split[currentWord] = new char[end - last]; + System.arraycopy(array, last, split[currentWord], 0, end - last); + return split; + } + + /** + * Answers a new array which is a copy of the given array starting at the given start and + * ending at the given end. The given start is inclusive and the given end is exclusive. + * Answers null if start is greater than end, if start is lower than 0 or if end is greater + * than the length of the given array. If end equals -1, it is converted to the array length. + *
+ *
+ * For example: + *
    + *
  1. +	 *    array = { { 'a' } , { 'b' } }
    +	 *    start = 0
    +	 *    end = 1
    +	 *    result => { { 'a' } }
    +	 * 
    + *
  2. + *
  3. +	 *    array = { { 'a' } , { 'b' } }
    +	 *    start = 0
    +	 *    end = -1
    +	 *    result => { { 'a' }, { 'b' } }
    +	 * 
    + *
  4. + *
+ * + * @param array the given array + * @param start the given starting index + * @param end the given ending index + * @return a new array which is a copy of the given array starting at the given start and + * ending at the given end + * @throws NullPointerException if the given array is null + */ + public static final char[][] subarray(char[][] array, int start, int end) { + if (end == -1) + end = array.length; + if (start > end) + return null; + if (start < 0) + return null; + if (end > array.length) + return null; + + char[][] result = new char[end - start][]; + System.arraycopy(array, start, result, 0, end - start); + return result; + } + + /** + * Answers a new array which is a copy of the given array starting at the given start and + * ending at the given end. The given start is inclusive and the given end is exclusive. + * Answers null if start is greater than end, if start is lower than 0 or if end is greater + * than the length of the given array. If end equals -1, it is converted to the array length. + *
+ *
+ * For example: + *
    + *
  1. +	 *    array = { 'a' , 'b' }
    +	 *    start = 0
    +	 *    end = 1
    +	 *    result => { 'a' }
    +	 * 
    + *
  2. + *
  3. +	 *    array = { 'a', 'b' }
    +	 *    start = 0
    +	 *    end = -1
    +	 *    result => { 'a' , 'b' }
    +	 * 
    + *
  4. + *
+ * + * @param array the given array + * @param start the given starting index + * @param end the given ending index + * @return a new array which is a copy of the given array starting at the given start and + * ending at the given end + * @throws NullPointerException if the given array is null + */ + public static final char[] subarray(char[] array, int start, int end) { + if (end == -1) + end = array.length; + if (start > end) + return null; + if (start < 0) + return null; + if (end > array.length) + return null; + + char[] result = new char[end - start]; + System.arraycopy(array, start, result, 0, end - start); + return result; + } + /** + * Answers the result of a char[] conversion to lowercase. Answers null if the given chars array is null. + *
+ * NOTE: If no conversion was necessary, then answers back the argument one. + *
+ *
+ * For example: + *
    + *
  1. +	 *    chars = { 'a' , 'b' }
    +	 *    result => { 'a' , 'b' }
    +	 * 
    + *
  2. + *
  3. +	 *    array = { 'A', 'b' }
    +	 *    result => { 'a' , 'b' }
    +	 * 
    + *
  4. + *
+ * + * @param chars the chars to convert + * @return the result of a char[] conversion to lowercase + */ + final static public char[] toLowerCase(char[] chars) { + if (chars == null) + return null; + int length = chars.length; + char[] lowerChars = null; + for (int i = 0; i < length; i++) { + char c = chars[i]; + char lc = Character.toLowerCase(c); + if ((c != lc) || (lowerChars != null)) { + if (lowerChars == null) { + System.arraycopy( + chars, + 0, + lowerChars = new char[length], + 0, + i); + } + lowerChars[i] = lc; + } + } + return lowerChars == null ? chars : lowerChars; + } + + /** + * Answers a new array removing leading and trailing spaces (' '). Answers the given array if there is no + * space characters to remove. + *
+ *
+ * For example: + *
    + *
  1. +	 *    chars = { ' ', 'a' , 'b', ' ',  ' ' }
    +	 *    result => { 'a' , 'b' }
    +	 * 
    + *
  2. + *
  3. +	 *    array = { 'A', 'b' }
    +	 *    result => { 'A' , 'b' }
    +	 * 
    + *
  4. + *
+ * + * @param chars the given array + * @return a new array removing leading and trailing spaces (' ') + */ + final static public char[] trim(char[] chars) { + + if (chars == null) + return null; + + int start = 0, length = chars.length, end = length - 1; + while (start < length && chars[start] == ' ') { + start++; + } + while (end > start && chars[end] == ' ') { + end--; + } + if (start != 0 || end != length - 1) { + return subarray(chars, start, end + 1); + } + return chars; + } + + /** + * Answers a string which is the concatenation of the given array using the '.' as a separator. + *
+ *
+ * For example: + *
    + *
  1. +	 *    array = { { 'a' } , { 'b' } }
    +	 *    result => "a.b"
    +	 * 
    + *
  2. + *
  3. +	 *    array = { { ' ',  'a' } , { 'b' } }
    +	 *    result => " a.b"
    +	 * 
    + *
  4. + *
+ * + * @param array the given array + * @return a string which is the concatenation of the given array using the '.' as a separator + */ + final static public String toString(char[][] array) { + char[] result = concatWith(array, '.'); + return new String(result); + } + /** + * Answers an array of strings from the given array of char array. + * + * @param array the given array + * @return an array of strings + * @since 3.0 + */ + final static public String[] toStrings(char[][] array) { + int length = array.length; + String[] result = new String[length]; + for (int i = 0; i < length; i++) + result[i] = new String(array[i]); + return result; + } +} diff --git a/src/java/org/eclipse/jdt/core/compiler/IProblem.java b/src/java/org/eclipse/jdt/core/compiler/IProblem.java new file mode 100644 index 0000000..7be59f1 --- /dev/null +++ b/src/java/org/eclipse/jdt/core/compiler/IProblem.java @@ -0,0 +1,800 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * IBM Corporation - added the following constants + * NonStaticAccessToStaticField + * NonStaticAccessToStaticMethod + * Task + * ExpressionShouldBeAVariable + * AssignmentHasNoEffect + * IBM Corporation - added the following constants + * TooManySyntheticArgumentSlots + * TooManyArrayDimensions + * TooManyBytesForStringConstant + * TooManyMethods + * TooManyFields + * NonBlankFinalLocalAssignment + * ObjectCannotHaveSuperTypes + * MissingSemiColon + * InvalidParenthesizedExpression + * EnclosingInstanceInConstructorCall + * BytecodeExceeds64KLimitForConstructor + * IncompatibleReturnTypeForNonInheritedInterfaceMethod + * UnusedPrivateMethod + * UnusedPrivateConstructor + * UnusedPrivateType + * UnusedPrivateField + * IncompatibleExceptionInThrowsClauseForNonInheritedInterfaceMethod + * InvalidExplicitConstructorCall + * IBM Corporation - added the following constants + * PossibleAccidentalBooleanAssignment + * SuperfluousSemicolon + * IndirectAccessToStaticField + * IndirectAccessToStaticMethod + * IndirectAccessToStaticType + * BooleanMethodThrowingException + * UnnecessaryCast + * UnnecessaryArgumentCast + * UnnecessaryInstanceof + * FinallyMustCompleteNormally + * UnusedMethodDeclaredThrownException + * UnusedConstructorDeclaredThrownException + * InvalidCatchBlockSequence + * UnqualifiedFieldAccess + * IBM Corporation - added the following constants + * Javadoc + * JavadocUnexpectedTag + * JavadocMissingParamTag + * JavadocMissingParamName + * JavadocDuplicateParamName + * JavadocInvalidParamName + * JavadocMissingReturnTag + * JavadocDuplicateReturnTag + * JavadocMissingThrowsTag + * JavadocMissingThrowsClassName + * JavadocInvalidThrowsClass + * JavadocDuplicateThrowsClassName + * JavadocInvalidThrowsClassName + * JavadocMissingSeeReference + * JavadocInvalidSeeReference + * JavadocInvalidSeeHref + * JavadocInvalidSeeArgs + * JavadocMissing + * JavadocInvalidTag + * JavadocMessagePrefix + * EmptyControlFlowStatement + ****************************************************************************/ +package org.eclipse.jdt.core.compiler; + +import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons; + +/** + * Description of a Java problem, as detected by the compiler or some of the underlying + * technology reusing the compiler. + * A problem provides access to: + * + * + * Note: the compiler produces IProblems internally, which are turned into markers by the JavaBuilder + * so as to persist problem descriptions. This explains why there is no API allowing to reach IProblem detected + * when compiling. However, the Java problem markers carry equivalent information to IProblem, in particular + * their ID (attribute "id") is set to one of the IDs defined on this interface. + * + * @since 2.0 + */ +public interface IProblem { + + /** + * Answer back the original arguments recorded into the problem. + * @return the original arguments recorded into the problem + */ + String[] getArguments(); + + /** + * Returns the problem id + * + * @return the problem id + */ + int getID(); + + /** + * Answer a localized, human-readable message string which describes the problem. + * + * @return a localized, human-readable message string which describes the problem + */ + String getMessage(); + + /** + * Answer the file name in which the problem was found. + * + * @return the file name in which the problem was found + */ + char[] getOriginatingFileName(); + + /** + * Answer the end position of the problem (inclusive), or -1 if unknown. + * + * @return the end position of the problem (inclusive), or -1 if unknown + */ + int getSourceEnd(); + + /** + * Answer the line number in source where the problem begins. + * + * @return the line number in source where the problem begins + */ + int getSourceLineNumber(); + + /** + * Answer the start position of the problem (inclusive), or -1 if unknown. + * + * @return the start position of the problem (inclusive), or -1 if unknown + */ + int getSourceStart(); + + /** + * Checks the severity to see if the Error bit is set. + * + * @return true if the Error bit is set for the severity, false otherwise + */ + boolean isError(); + + /** + * Checks the severity to see if the Error bit is not set. + * + * @return true if the Error bit is not set for the severity, false otherwise + */ + boolean isWarning(); + + /** + * Set the end position of the problem (inclusive), or -1 if unknown. + * Used for shifting problem positions. + * + * @param sourceEnd the given end position + */ + void setSourceEnd(int sourceEnd); + + /** + * Set the line number in source where the problem begins. + * + * @param lineNumber the given line number + */ + void setSourceLineNumber(int lineNumber); + + /** + * Set the start position of the problem (inclusive), or -1 if unknown. + * Used for shifting problem positions. + * + * @param sourceStart the given start position + */ + void setSourceStart(int sourceStart); + + /** + * Problem Categories + * The high bits of a problem ID contains information about the category of a problem. + * For example, (problemID & TypeRelated) != 0, indicates that this problem is type related. + * + * A problem category can help to implement custom problem filters. Indeed, when numerous problems + * are listed, focusing on import related problems first might be relevant. + * + * When a problem is tagged as Internal, it means that no change other than a local source code change + * can fix the corresponding problem. + */ + int TypeRelated = 0x01000000; + int FieldRelated = 0x02000000; + int MethodRelated = 0x04000000; + int ConstructorRelated = 0x08000000; + int ImportRelated = 0x10000000; + int Internal = 0x20000000; + int Syntax = 0x40000000; + /** + * @since 3.0 + */ + int Javadoc = 0x80000000; + + /** + * Mask to use in order to filter out the category portion of the problem ID. + */ + int IgnoreCategoriesMask = 0xFFFFFF; + + /** + * Below are listed all available problem IDs. Note that this list could be augmented in the future, + * as new features are added to the Java core implementation. + */ + + /** + * ID reserved for referencing an internal error inside the JavaCore implementation which + * may be surfaced as a problem associated with the compilation unit which caused it to occur. + */ + int Unclassified = 0; + + /** + * General type related problems + */ + int ObjectHasNoSuperclass = TypeRelated + 1; + int UndefinedType = TypeRelated + 2; + int NotVisibleType = TypeRelated + 3; + int AmbiguousType = TypeRelated + 4; + int UsingDeprecatedType = TypeRelated + 5; + int InternalTypeNameProvided = TypeRelated + 6; + /** @since 2.1 */ + int UnusedPrivateType = Internal + TypeRelated + 7; + + int IncompatibleTypesInEqualityOperator = TypeRelated + 15; + int IncompatibleTypesInConditionalOperator = TypeRelated + 16; + int TypeMismatch = TypeRelated + 17; + /** @since 3.0 */ + int IndirectAccessToStaticType = Internal + TypeRelated + 18; + + /** + * Inner types related problems + */ + int MissingEnclosingInstanceForConstructorCall = TypeRelated + 20; + int MissingEnclosingInstance = TypeRelated + 21; + int IncorrectEnclosingInstanceReference = TypeRelated + 22; + int IllegalEnclosingInstanceSpecification = TypeRelated + 23; + int CannotDefineStaticInitializerInLocalType = Internal + 24; + int OuterLocalMustBeFinal = Internal + 25; + int CannotDefineInterfaceInLocalType = Internal + 26; + int IllegalPrimitiveOrArrayTypeForEnclosingInstance = TypeRelated + 27; + /** @since 2.1 */ + int EnclosingInstanceInConstructorCall = Internal + 28; + int AnonymousClassCannotExtendFinalClass = TypeRelated + 29; + + // variables + int UndefinedName = 50; + int UninitializedLocalVariable = Internal + 51; + int VariableTypeCannotBeVoid = Internal + 52; + int VariableTypeCannotBeVoidArray = Internal + 53; + int CannotAllocateVoidArray = Internal + 54; + // local variables + int RedefinedLocal = Internal + 55; + int RedefinedArgument = Internal + 56; + // final local variables + int DuplicateFinalLocalInitialization = Internal + 57; + /** @since 2.1 */ + int NonBlankFinalLocalAssignment = Internal + 58; + + int FinalOuterLocalAssignment = Internal + 60; + int LocalVariableIsNeverUsed = Internal + 61; + int ArgumentIsNeverUsed = Internal + 62; + int BytecodeExceeds64KLimit = Internal + 63; + int BytecodeExceeds64KLimitForClinit = Internal + 64; + int TooManyArgumentSlots = Internal + 65; + int TooManyLocalVariableSlots = Internal + 66; + /** @since 2.1 */ + int TooManySyntheticArgumentSlots = Internal + 67; + /** @since 2.1 */ + int TooManyArrayDimensions = Internal + 68; + /** @since 2.1 */ + int BytecodeExceeds64KLimitForConstructor = Internal + 69; + + // fields + int UndefinedField = FieldRelated + 70; + int NotVisibleField = FieldRelated + 71; + int AmbiguousField = FieldRelated + 72; + int UsingDeprecatedField = FieldRelated + 73; + int NonStaticFieldFromStaticInvocation = FieldRelated + 74; + int ReferenceToForwardField = FieldRelated + Internal + 75; + /** @since 2.1 */ + int NonStaticAccessToStaticField = Internal + FieldRelated + 76; + /** @since 2.1 */ + int UnusedPrivateField = Internal + FieldRelated + 77; + /** @since 3.0 */ + int IndirectAccessToStaticField = Internal + FieldRelated + 78; + /** @since 3.0 */ + int UnqualifiedFieldAccess = Internal + FieldRelated + 79; + + // blank final fields + int FinalFieldAssignment = FieldRelated + 80; + int UninitializedBlankFinalField = FieldRelated + 81; + int DuplicateBlankFinalFieldInitialization = FieldRelated + 82; + + // variable hiding + /** + * The local variable {0} is hiding another local variable defined in an enclosing type scope + * @since 3.0 + */ + int LocalVariableHidingLocalVariable = Internal + 90; + + /** + * The local variable {0} is hiding the field {1}.{2} + * @since 3.0 + */ + int LocalVariableHidingField = Internal + FieldRelated + 91; + + /** + * The field {0}.{1} is hiding another local variable defined in an enclosing type scope + * @since 3.0 + */ + int FieldHidingLocalVariable = Internal + FieldRelated + 92; + + /** + * The field {0}.{1} is hiding the field {2}.{3} + * @since 3.0 + */ + int FieldHidingField = Internal + FieldRelated + 93; + + /** + * The argument {0} is hiding another local variable defined in an enclosing type scope + * @since 3.0 + */ + int ArgumentHidingLocalVariable = Internal + 94; + + /** + * The argument {0} is hiding the field {2}.{3} + * @since 3.0 + */ + int ArgumentHidingField = Internal + 95; + + // methods + int UndefinedMethod = MethodRelated + 100; + int NotVisibleMethod = MethodRelated + 101; + int AmbiguousMethod = MethodRelated + 102; + int UsingDeprecatedMethod = MethodRelated + 103; + int DirectInvocationOfAbstractMethod = MethodRelated + 104; + int VoidMethodReturnsValue = MethodRelated + 105; + int MethodReturnsVoid = MethodRelated + 106; + int MethodRequiresBody = Internal + MethodRelated + 107; + int ShouldReturnValue = Internal + MethodRelated + 108; + int MethodButWithConstructorName = MethodRelated + 110; + int MissingReturnType = TypeRelated + 111; + int BodyForNativeMethod = Internal + MethodRelated + 112; + int BodyForAbstractMethod = Internal + MethodRelated + 113; + int NoMessageSendOnBaseType = MethodRelated + 114; + int ParameterMismatch = MethodRelated + 115; + int NoMessageSendOnArrayType = MethodRelated + 116; + /** @since 2.1 */ + int NonStaticAccessToStaticMethod = Internal + MethodRelated + 117; + /** @since 2.1 */ + int UnusedPrivateMethod = Internal + MethodRelated + 118; + /** @since 3.0 */ + int IndirectAccessToStaticMethod = Internal + MethodRelated + 119; + + + // constructors + int UndefinedConstructor = ConstructorRelated + 130; + int NotVisibleConstructor = ConstructorRelated + 131; + int AmbiguousConstructor = ConstructorRelated + 132; + int UsingDeprecatedConstructor = ConstructorRelated + 133; + /** @since 2.1 */ + int UnusedPrivateConstructor = Internal + MethodRelated + 134; + // explicit constructor calls + int InstanceFieldDuringConstructorInvocation = ConstructorRelated + 135; + int InstanceMethodDuringConstructorInvocation = ConstructorRelated + 136; + int RecursiveConstructorInvocation = ConstructorRelated + 137; + int ThisSuperDuringConstructorInvocation = ConstructorRelated + 138; + /** @since 3.0 */ + int InvalidExplicitConstructorCall = ConstructorRelated + Syntax + 139; + // implicit constructor calls + int UndefinedConstructorInDefaultConstructor = ConstructorRelated + 140; + int NotVisibleConstructorInDefaultConstructor = ConstructorRelated + 141; + int AmbiguousConstructorInDefaultConstructor = ConstructorRelated + 142; + int UndefinedConstructorInImplicitConstructorCall = ConstructorRelated + 143; + int NotVisibleConstructorInImplicitConstructorCall = ConstructorRelated + 144; + int AmbiguousConstructorInImplicitConstructorCall = ConstructorRelated + 145; + int UnhandledExceptionInDefaultConstructor = TypeRelated + 146; + int UnhandledExceptionInImplicitConstructorCall = TypeRelated + 147; + + // expressions + int ArrayReferenceRequired = Internal + 150; + int NoImplicitStringConversionForCharArrayExpression = Internal + 151; + // constant expressions + int StringConstantIsExceedingUtf8Limit = Internal + 152; + int NonConstantExpression = 153; + int NumericValueOutOfRange = Internal + 154; + // cast expressions + int IllegalCast = TypeRelated + 156; + // allocations + int InvalidClassInstantiation = TypeRelated + 157; + int CannotDefineDimensionExpressionsWithInit = Internal + 158; + int MustDefineEitherDimensionExpressionsOrInitializer = Internal + 159; + // operators + int InvalidOperator = Internal + 160; + // statements + int CodeCannotBeReached = Internal + 161; + int CannotReturnInInitializer = Internal + 162; + int InitializerMustCompleteNormally = Internal + 163; + // assert + int InvalidVoidExpression = Internal + 164; + // try + int MaskedCatch = TypeRelated + 165; + int DuplicateDefaultCase = 166; + int UnreachableCatch = TypeRelated + MethodRelated + 167; + int UnhandledException = TypeRelated + 168; + // switch + int IncorrectSwitchType = TypeRelated + 169; + int DuplicateCase = FieldRelated + 170; + // labelled + int DuplicateLabel = Internal + 171; + int InvalidBreak = Internal + 172; + int InvalidContinue = Internal + 173; + int UndefinedLabel = Internal + 174; + //synchronized + int InvalidTypeToSynchronized = Internal + 175; + int InvalidNullToSynchronized = Internal + 176; + // throw + int CannotThrowNull = Internal + 177; + // assignment + /** @since 2.1 */ + int AssignmentHasNoEffect = Internal + 178; + /** @since 3.0 */ + int PossibleAccidentalBooleanAssignment = Internal + 179; + /** @since 3.0 */ + int SuperfluousSemicolon = Internal + 180; + /** @since 3.0 */ + int UnnecessaryCast = Internal + TypeRelated + 181; + /** @since 3.0 */ + int UnnecessaryArgumentCast = Internal + TypeRelated + 182; + /** @since 3.0 */ + int UnnecessaryInstanceof = Internal + TypeRelated + 183; + /** @since 3.0 */ + int FinallyMustCompleteNormally = Internal + 184; + /** @since 3.0 */ + int UnusedMethodDeclaredThrownException = Internal + 185; + /** @since 3.0 */ + int UnusedConstructorDeclaredThrownException = Internal + 186; + /** @since 3.0 */ + int InvalidCatchBlockSequence = Internal + TypeRelated + 187; + /** @since 3.0 */ + int EmptyControlFlowStatement = Internal + TypeRelated + 188; + /** @since 3.0 */ + int UnnecessaryElse = Internal + 189; + + // inner emulation + int NeedToEmulateFieldReadAccess = FieldRelated + 190; + int NeedToEmulateFieldWriteAccess = FieldRelated + 191; + int NeedToEmulateMethodAccess = MethodRelated + 192; + int NeedToEmulateConstructorAccess = MethodRelated + 193; + + //inherited name hides enclosing name (sort of ambiguous) + int InheritedMethodHidesEnclosingName = MethodRelated + 195; + int InheritedFieldHidesEnclosingName = FieldRelated + 196; + int InheritedTypeHidesEnclosingName = TypeRelated + 197; + + // miscellaneous + int ThisInStaticContext = Internal + 200; + int StaticMethodRequested = Internal + MethodRelated + 201; + int IllegalDimension = Internal + 202; + int InvalidTypeExpression = Internal + 203; + int ParsingError = Syntax + Internal + 204; + int ParsingErrorNoSuggestion = Syntax + Internal + 205; + int InvalidUnaryExpression = Syntax + Internal + 206; + + // syntax errors + int InterfaceCannotHaveConstructors = Syntax + Internal + 207; + int ArrayConstantsOnlyInArrayInitializers = Syntax + Internal + 208; + int ParsingErrorOnKeyword = Syntax + Internal + 209; + int ParsingErrorOnKeywordNoSuggestion = Syntax + Internal + 210; + + int UnmatchedBracket = Syntax + Internal + 220; + int NoFieldOnBaseType = FieldRelated + 221; + int InvalidExpressionAsStatement = Syntax + Internal + 222; + /** @since 2.1 */ + int ExpressionShouldBeAVariable = Syntax + Internal + 223; + /** @since 2.1 */ + int MissingSemiColon = Syntax + Internal + 224; + /** @since 2.1 */ + int InvalidParenthesizedExpression = Syntax + Internal + 225; + + /** @since 3.0 */ + int ParsingErrorInsertTokenBefore = Syntax + Internal + 230; + /** @since 3.0 */ + int ParsingErrorInsertTokenAfter = Syntax + Internal + 231; + /** @since 3.0 */ + int ParsingErrorDeleteToken = Syntax + Internal + 232; + /** @since 3.0 */ + int ParsingErrorDeleteTokens = Syntax + Internal + 233; + /** @since 3.0 */ + int ParsingErrorMergeTokens = Syntax + Internal + 234; + /** @since 3.0 */ + int ParsingErrorInvalidToken = Syntax + Internal + 235; + /** @since 3.0 */ + int ParsingErrorMisplacedConstruct = Syntax + Internal + 236; + /** @since 3.0 */ + int ParsingErrorReplaceTokens = Syntax + Internal + 237; + /** @since 3.0 */ + int ParsingErrorNoSuggestionForTokens = Syntax + Internal + 238; + /** @since 3.0 */ + int ParsingErrorUnexpectedEOF = Syntax + Internal + 239; + /** @since 3.0 */ + int ParsingErrorInsertToComplete = Syntax + Internal + 240; + /** @since 3.0 */ + int ParsingErrorInsertToCompleteScope = Syntax + Internal + 241; + /** @since 3.0 */ + int ParsingErrorInsertToCompletePhrase = Syntax + Internal + 242; + + // scanner errors + int EndOfSource = Syntax + Internal + 250; + int InvalidHexa = Syntax + Internal + 251; + int InvalidOctal = Syntax + Internal + 252; + int InvalidCharacterConstant = Syntax + Internal + 253; + int InvalidEscape = Syntax + Internal + 254; + int InvalidInput = Syntax + Internal + 255; + int InvalidUnicodeEscape = Syntax + Internal + 256; + int InvalidFloat = Syntax + Internal + 257; + int NullSourceString = Syntax + Internal + 258; + int UnterminatedString = Syntax + Internal + 259; + int UnterminatedComment = Syntax + Internal + 260; + + // type related problems + int InterfaceCannotHaveInitializers = TypeRelated + 300; + int DuplicateModifierForType = TypeRelated + 301; + int IllegalModifierForClass = TypeRelated + 302; + int IllegalModifierForInterface = TypeRelated + 303; + int IllegalModifierForMemberClass = TypeRelated + 304; + int IllegalModifierForMemberInterface = TypeRelated + 305; + int IllegalModifierForLocalClass = TypeRelated + 306; + + int IllegalModifierCombinationFinalAbstractForClass = TypeRelated + 308; + int IllegalVisibilityModifierForInterfaceMemberType = TypeRelated + 309; + int IllegalVisibilityModifierCombinationForMemberType = TypeRelated + 310; + int IllegalStaticModifierForMemberType = TypeRelated + 311; + int SuperclassMustBeAClass = TypeRelated + 312; + int ClassExtendFinalClass = TypeRelated + 313; + int DuplicateSuperInterface = TypeRelated + 314; + int SuperInterfaceMustBeAnInterface = TypeRelated + 315; + int HierarchyCircularitySelfReference = TypeRelated + 316; + int HierarchyCircularity = TypeRelated + 317; + int HidingEnclosingType = TypeRelated + 318; + int DuplicateNestedType = TypeRelated + 319; + int CannotThrowType = TypeRelated + 320; + int PackageCollidesWithType = TypeRelated + 321; + int TypeCollidesWithPackage = TypeRelated + 322; + int DuplicateTypes = TypeRelated + 323; + int IsClassPathCorrect = TypeRelated + 324; + int PublicClassMustMatchFileName = TypeRelated + 325; + int MustSpecifyPackage = 326; + int HierarchyHasProblems = TypeRelated + 327; + int PackageIsNotExpectedPackage = 328; + /** @since 2.1 */ + int ObjectCannotHaveSuperTypes = 329; + + // int InvalidSuperclassBase = TypeRelated + 329; // reserved to 334 included + int SuperclassNotFound = TypeRelated + 329 + ProblemReasons.NotFound; // TypeRelated + 330 + int SuperclassNotVisible = TypeRelated + 329 + ProblemReasons.NotVisible; // TypeRelated + 331 + int SuperclassAmbiguous = TypeRelated + 329 + ProblemReasons.Ambiguous; // TypeRelated + 332 + int SuperclassInternalNameProvided = TypeRelated + 329 + ProblemReasons.InternalNameProvided; // TypeRelated + 333 + int SuperclassInheritedNameHidesEnclosingName = TypeRelated + 329 + ProblemReasons.InheritedNameHidesEnclosingName; // TypeRelated + 334 + + // int InvalidInterfaceBase = TypeRelated + 334; // reserved to 339 included + int InterfaceNotFound = TypeRelated + 334 + ProblemReasons.NotFound; // TypeRelated + 335 + int InterfaceNotVisible = TypeRelated + 334 + ProblemReasons.NotVisible; // TypeRelated + 336 + int InterfaceAmbiguous = TypeRelated + 334 + ProblemReasons.Ambiguous; // TypeRelated + 337 + int InterfaceInternalNameProvided = TypeRelated + 334 + ProblemReasons.InternalNameProvided; // TypeRelated + 338 + int InterfaceInheritedNameHidesEnclosingName = TypeRelated + 334 + ProblemReasons.InheritedNameHidesEnclosingName; // TypeRelated + 339 + + // field related problems + int DuplicateField = FieldRelated + 340; + int DuplicateModifierForField = FieldRelated + 341; + int IllegalModifierForField = FieldRelated + 342; + int IllegalModifierForInterfaceField = FieldRelated + 343; + int IllegalVisibilityModifierCombinationForField = FieldRelated + 344; + int IllegalModifierCombinationFinalVolatileForField = FieldRelated + 345; + int UnexpectedStaticModifierForField = FieldRelated + 346; + + // int FieldTypeProblemBase = FieldRelated + 349; //reserved to 354 + int FieldTypeNotFound = FieldRelated + 349 + ProblemReasons.NotFound; // FieldRelated + 350 + int FieldTypeNotVisible = FieldRelated + 349 + ProblemReasons.NotVisible; // FieldRelated + 351 + int FieldTypeAmbiguous = FieldRelated + 349 + ProblemReasons.Ambiguous; // FieldRelated + 352 + int FieldTypeInternalNameProvided = FieldRelated + 349 + ProblemReasons.InternalNameProvided; // FieldRelated + 353 + int FieldTypeInheritedNameHidesEnclosingName = FieldRelated + 349 + ProblemReasons.InheritedNameHidesEnclosingName; // FieldRelated + 354 + + // method related problems + int DuplicateMethod = MethodRelated + 355; + int IllegalModifierForArgument = MethodRelated + 356; + int DuplicateModifierForMethod = MethodRelated + 357; + int IllegalModifierForMethod = MethodRelated + 358; + int IllegalModifierForInterfaceMethod = MethodRelated + 359; + int IllegalVisibilityModifierCombinationForMethod = MethodRelated + 360; + int UnexpectedStaticModifierForMethod = MethodRelated + 361; + int IllegalAbstractModifierCombinationForMethod = MethodRelated + 362; + int AbstractMethodInAbstractClass = MethodRelated + 363; + int ArgumentTypeCannotBeVoid = MethodRelated + 364; + int ArgumentTypeCannotBeVoidArray = MethodRelated + 365; + int ReturnTypeCannotBeVoidArray = MethodRelated + 366; + int NativeMethodsCannotBeStrictfp = MethodRelated + 367; + int DuplicateModifierForArgument = MethodRelated + 368; + + // int ArgumentProblemBase = MethodRelated + 369; // reserved to 374 included. + int ArgumentTypeNotFound = MethodRelated + 369 + ProblemReasons.NotFound; // MethodRelated + 370 + int ArgumentTypeNotVisible = MethodRelated + 369 + ProblemReasons.NotVisible; // MethodRelated + 371 + int ArgumentTypeAmbiguous = MethodRelated + 369 + ProblemReasons.Ambiguous; // MethodRelated + 372 + int ArgumentTypeInternalNameProvided = MethodRelated + 369 + ProblemReasons.InternalNameProvided; // MethodRelated + 373 + int ArgumentTypeInheritedNameHidesEnclosingName = MethodRelated + 369 + ProblemReasons.InheritedNameHidesEnclosingName; // MethodRelated + 374 + + // int ExceptionTypeProblemBase = MethodRelated + 374; // reserved to 379 included. + int ExceptionTypeNotFound = MethodRelated + 374 + ProblemReasons.NotFound; // MethodRelated + 375 + int ExceptionTypeNotVisible = MethodRelated + 374 + ProblemReasons.NotVisible; // MethodRelated + 376 + int ExceptionTypeAmbiguous = MethodRelated + 374 + ProblemReasons.Ambiguous; // MethodRelated + 377 + int ExceptionTypeInternalNameProvided = MethodRelated + 374 + ProblemReasons.InternalNameProvided; // MethodRelated + 378 + int ExceptionTypeInheritedNameHidesEnclosingName = MethodRelated + 374 + ProblemReasons.InheritedNameHidesEnclosingName; // MethodRelated + 379 + + // int ReturnTypeProblemBase = MethodRelated + 379; + int ReturnTypeNotFound = MethodRelated + 379 + ProblemReasons.NotFound; // MethodRelated + 380 + int ReturnTypeNotVisible = MethodRelated + 379 + ProblemReasons.NotVisible; // MethodRelated + 381 + int ReturnTypeAmbiguous = MethodRelated + 379 + ProblemReasons.Ambiguous; // MethodRelated + 382 + int ReturnTypeInternalNameProvided = MethodRelated + 379 + ProblemReasons.InternalNameProvided; // MethodRelated + 383 + int ReturnTypeInheritedNameHidesEnclosingName = MethodRelated + 379 + ProblemReasons.InheritedNameHidesEnclosingName; // MethodRelated + 384 + + // import related problems + int ConflictingImport = ImportRelated + 385; + int DuplicateImport = ImportRelated + 386; + int CannotImportPackage = ImportRelated + 387; + int UnusedImport = ImportRelated + 388; + + // int ImportProblemBase = ImportRelated + 389; + int ImportNotFound = ImportRelated + 389 + ProblemReasons.NotFound; // ImportRelated + 390 + int ImportNotVisible = ImportRelated + 389 + ProblemReasons.NotVisible; // ImportRelated + 391 + int ImportAmbiguous = ImportRelated + 389 + ProblemReasons.Ambiguous; // ImportRelated + 392 + int ImportInternalNameProvided = ImportRelated + 389 + ProblemReasons.InternalNameProvided; // ImportRelated + 393 + int ImportInheritedNameHidesEnclosingName = ImportRelated + 389 + ProblemReasons.InheritedNameHidesEnclosingName; // ImportRelated + 394 + + // local variable related problems + int DuplicateModifierForVariable = MethodRelated + 395; + int IllegalModifierForVariable = MethodRelated + 396; + + // method verifier problems + int AbstractMethodMustBeImplemented = MethodRelated + 400; + int FinalMethodCannotBeOverridden = MethodRelated + 401; + int IncompatibleExceptionInThrowsClause = MethodRelated + 402; + int IncompatibleExceptionInInheritedMethodThrowsClause = MethodRelated + 403; + int IncompatibleReturnType = MethodRelated + 404; + int InheritedMethodReducesVisibility = MethodRelated + 405; + int CannotOverrideAStaticMethodWithAnInstanceMethod = MethodRelated + 406; + int CannotHideAnInstanceMethodWithAStaticMethod = MethodRelated + 407; + int StaticInheritedMethodConflicts = MethodRelated + 408; + int MethodReducesVisibility = MethodRelated + 409; + int OverridingNonVisibleMethod = MethodRelated + 410; + int AbstractMethodCannotBeOverridden = MethodRelated + 411; + int OverridingDeprecatedMethod = MethodRelated + 412; + /** @since 2.1 */ + int IncompatibleReturnTypeForNonInheritedInterfaceMethod = MethodRelated + 413; + /** @since 2.1 */ + int IncompatibleExceptionInThrowsClauseForNonInheritedInterfaceMethod = MethodRelated + 414; + + // code snippet support + int CodeSnippetMissingClass = Internal + 420; + int CodeSnippetMissingMethod = Internal + 421; + int NonExternalizedStringLiteral = Internal + 261; + int CannotUseSuperInCodeSnippet = Internal + 422; + + //constant pool + int TooManyConstantsInConstantPool = Internal + 430; + /** @since 2.1 */ + int TooManyBytesForStringConstant = Internal + 431; + + // static constraints + /** @since 2.1 */ + int TooManyFields = Internal + 432; + /** @since 2.1 */ + int TooManyMethods = Internal + 433; + + // 1.4 features + // assertion warning + int UseAssertAsAnIdentifier = Internal + 440; + + // detected task + /** @since 2.1 */ + int Task = Internal + 450; + + // block + /** @since 3.0 */ + int UndocumentedEmptyBlock = Internal + 460; + + /* + * Javadoc comments + */ + /** @since 3.0 */ + int JavadocUnexpectedTag = Javadoc + Internal + 470; + /** @since 3.0 */ + int JavadocMissingParamTag = Javadoc + Internal + 471; + /** @since 3.0 */ + int JavadocMissingParamName = Javadoc + Internal + 472; + /** @since 3.0 */ + int JavadocDuplicateParamName = Javadoc + Internal + 473; + /** @since 3.0 */ + int JavadocInvalidParamName = Javadoc + Internal + 474; + /** @since 3.0 */ + int JavadocMissingReturnTag = Javadoc + Internal + 475; + /** @since 3.0 */ + int JavadocDuplicateReturnTag = Javadoc + Internal + 476; + /** @since 3.0 */ + int JavadocMissingThrowsTag = Javadoc + Internal + 477; + /** @since 3.0 */ + int JavadocMissingThrowsClassName = Javadoc + Internal + 478; + /** @since 3.0 */ + int JavadocInvalidThrowsClass = Javadoc + Internal + 479; + /** @since 3.0 */ + int JavadocDuplicateThrowsClassName = Javadoc + Internal + 480; + /** @since 3.0 */ + int JavadocInvalidThrowsClassName = Javadoc + Internal + 481; + /** @since 3.0 */ + int JavadocMissingSeeReference = Javadoc + Internal + 482; + /** @since 3.0 */ + int JavadocInvalidSeeReference = Javadoc + Internal + 483; + /** @since 3.0 */ + int JavadocInvalidSeeHref = Javadoc + Internal + 484; + /** @since 3.0 */ + int JavadocInvalidSeeArgs = Javadoc + Internal + 485; + /** @since 3.0 */ + int JavadocMissing = Javadoc + Internal + 486; + /** @since 3.0 */ + int JavadocInvalidTag = Javadoc + Internal + 487; + /* + * ID for field errors in Javadoc + */ + /** @since 3.0 */ + int JavadocUndefinedField = Javadoc + Internal + 488; + /** @since 3.0 */ + int JavadocNotVisibleField = Javadoc + Internal + 489; + /** @since 3.0 */ + int JavadocAmbiguousField = Javadoc + Internal + 490; + /** @since 3.0 */ + int JavadocUsingDeprecatedField = Javadoc + Internal + 491; + /* + * IDs for constructor errors in Javadoc + */ + /** @since 3.0 */ + int JavadocUndefinedConstructor = Javadoc + Internal + 492; + /** @since 3.0 */ + int JavadocNotVisibleConstructor = Javadoc + Internal + 493; + /** @since 3.0 */ + int JavadocAmbiguousConstructor = Javadoc + Internal + 494; + /** @since 3.0 */ + int JavadocUsingDeprecatedConstructor = Javadoc + Internal + 495; + /* + * IDs for method errors in Javadoc + */ + /** @since 3.0 */ + int JavadocUndefinedMethod = Javadoc + Internal + 496; + /** @since 3.0 */ + int JavadocNotVisibleMethod = Javadoc + Internal + 497; + /** @since 3.0 */ + int JavadocAmbiguousMethod = Javadoc + Internal + 498; + /** @since 3.0 */ + int JavadocUsingDeprecatedMethod = Javadoc + Internal + 499; + /** @since 3.0 */ + int JavadocNoMessageSendOnBaseType = Javadoc + Internal + 500; + /** @since 3.0 */ + int JavadocParameterMismatch = Javadoc + Internal + 501; + /** @since 3.0 */ + int JavadocNoMessageSendOnArrayType = Javadoc + Internal + 502; + /* + * IDs for type errors in Javadoc + */ + /** @since 3.0 */ + int JavadocUndefinedType = Javadoc + Internal + 503; + /** @since 3.0 */ + int JavadocNotVisibleType = Javadoc + Internal + 504; + /** @since 3.0 */ + int JavadocAmbiguousType = Javadoc + Internal + 505; + /** @since 3.0 */ + int JavadocUsingDeprecatedType = Javadoc + Internal + 506; + /** @since 3.0 */ + int JavadocInternalTypeNameProvided = Javadoc + Internal + 507; + /** @since 3.0 */ + int JavadocInheritedMethodHidesEnclosingName = Javadoc + Internal + 508; + /** @since 3.0 */ + int JavadocInheritedFieldHidesEnclosingName = Javadoc + Internal + 509; + /** @since 3.0 */ + int JavadocInheritedNameHidesEnclosingTypeName = Javadoc + Internal + 510; + /** @since 3.0 */ + int JavadocAmbiguousMethodReference = Javadoc + Internal + 511; + /** @since 3.0 */ + int JavadocUnterminatedInlineTag = Javadoc + Internal + 512; + /** @since 3.0 */ + int JavadocMalformedSeeReference = Javadoc + Internal + 513; + /** @since 3.0 */ + int JavadocMessagePrefix = Internal + 515; +} diff --git a/src/java/org/eclipse/jdt/core/compiler/InvalidInputException.java b/src/java/org/eclipse/jdt/core/compiler/InvalidInputException.java new file mode 100644 index 0000000..7055b43 --- /dev/null +++ b/src/java/org/eclipse/jdt/core/compiler/InvalidInputException.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.compiler; + +/** + * Exception thrown by a scanner when encountering lexical errors. + */ +public class InvalidInputException extends Exception { + + private static final long serialVersionUID = 2909732853499731592L; // backward compatible + + /** + * Creates a new exception with no detail message. + */ + public InvalidInputException() { + super(); + } + /** + * Creates a new exception with the given detail message. + * @param message the detail message + */ + public InvalidInputException(String message) { + super(message); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ASTVisitor.java b/src/java/org/eclipse/jdt/internal/compiler/ASTVisitor.java new file mode 100644 index 0000000..9e1166d --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ASTVisitor.java @@ -0,0 +1,618 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler; + +import org.eclipse.jdt.core.compiler.*; +import org.eclipse.jdt.internal.compiler.ast.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +/** + * A visitor for iterating through the parse tree. + */ +public abstract class ASTVisitor { + + public void acceptProblem(IProblem problem) { + // do nothing by default + } + public void endVisit( + AllocationExpression allocationExpression, + BlockScope scope) { + // do nothing by default + } + public void endVisit(AND_AND_Expression and_and_Expression, BlockScope scope) { + // do nothing by default + } + public void endVisit(JavadocArrayQualifiedTypeReference typeRef, BlockScope scope) { + // do nothing by default + } + public void endVisit(JavadocArraySingleTypeReference typeRef, BlockScope scope) { + // do nothing by default + } + public void endVisit(JavadocArgumentExpression expression, BlockScope scope) { + // do nothing by default + } + public void endVisit(JavadocFieldReference fieldRef, BlockScope scope) { + // do nothing by default + } + public void endVisit(JavadocMessageSend messageSend, BlockScope scope) { + // do nothing by default + } + public void endVisit(JavadocQualifiedTypeReference typeRef, BlockScope scope) { + // do nothing by default + } + public void endVisit(JavadocReturnStatement statement, BlockScope scope) { + // do nothing by default + } + public void endVisit(JavadocSingleNameReference argument, BlockScope scope) { + // do nothing by default + } + public void endVisit(JavadocSingleTypeReference typeRef, BlockScope scope) { + // do nothing by default + } + public void endVisit(Argument argument, BlockScope scope) { + // do nothing by default + } + public void endVisit( + ArrayAllocationExpression arrayAllocationExpression, + BlockScope scope) { + // do nothing by default + } + public void endVisit(ArrayInitializer arrayInitializer, BlockScope scope) { + // do nothing by default + } + public void endVisit( + ArrayQualifiedTypeReference arrayQualifiedTypeReference, + BlockScope scope) { + // do nothing by default + } + public void endVisit( + ArrayQualifiedTypeReference arrayQualifiedTypeReference, + ClassScope scope) { + // do nothing by default + } + public void endVisit(ArrayReference arrayReference, BlockScope scope) { + // do nothing by default + } + public void endVisit(ArrayTypeReference arrayTypeReference, BlockScope scope) { + // do nothing by default + } + public void endVisit(ArrayTypeReference arrayTypeReference, ClassScope scope) { + // do nothing by default + } + public void endVisit(Assignment assignment, BlockScope scope) { + // do nothing by default + } + public void endVisit(AssertStatement assertStatement, BlockScope scope) { + // do nothing by default + } + public void endVisit(BinaryExpression binaryExpression, BlockScope scope) { + // do nothing by default + } + public void endVisit(Block block, BlockScope scope) { + // do nothing by default + } + public void endVisit(BreakStatement breakStatement, BlockScope scope) { + // do nothing by default + } + public void endVisit(CaseStatement caseStatement, BlockScope scope) { + // do nothing by default + } + public void endVisit(CastExpression castExpression, BlockScope scope) { + // do nothing by default + } + public void endVisit(CharLiteral charLiteral, BlockScope scope) { + // do nothing by default + } + public void endVisit(ClassLiteralAccess classLiteral, BlockScope scope) { + // do nothing by default + } + public void endVisit(Clinit clinit, ClassScope scope) { + // do nothing by default + } + public void endVisit( + CompilationUnitDeclaration compilationUnitDeclaration, + CompilationUnitScope scope) { + // do nothing by default + } + public void endVisit(CompoundAssignment compoundAssignment, BlockScope scope) { + // do nothing by default + } + public void endVisit( + ConditionalExpression conditionalExpression, + BlockScope scope) { + // do nothing by default + } + public void endVisit( + ConstructorDeclaration constructorDeclaration, + ClassScope scope) { + // do nothing by default + } + public void endVisit(ContinueStatement continueStatement, BlockScope scope) { + // do nothing by default + } + public void endVisit(DoStatement doStatement, BlockScope scope) { + // do nothing by default + } + public void endVisit(DoubleLiteral doubleLiteral, BlockScope scope) { + // do nothing by default + } + public void endVisit(EqualExpression equalExpression, BlockScope scope) { + // do nothing by default + } + public void endVisit( + ExplicitConstructorCall explicitConstructor, + BlockScope scope) { + // do nothing by default + } + public void endVisit( + ExtendedStringLiteral extendedStringLiteral, + BlockScope scope) { + // do nothing by default + } + public void endVisit(FalseLiteral falseLiteral, BlockScope scope) { + // do nothing by default + } + public void endVisit(FieldDeclaration fieldDeclaration, MethodScope scope) { + // do nothing by default + } + public void endVisit(FieldReference fieldReference, BlockScope scope) { + // do nothing by default + } + public void endVisit(FloatLiteral floatLiteral, BlockScope scope) { + // do nothing by default + } + public void endVisit(EmptyStatement emptyStatement, BlockScope scope) { + // do nothing by default + } + public void endVisit(ForStatement forStatement, BlockScope scope) { + // do nothing by default + } + public void endVisit(IfStatement ifStatement, BlockScope scope) { + // do nothing by default + } + public void endVisit(ImportReference importRef, CompilationUnitScope scope) { + // do nothing by default + } + public void endVisit(Initializer initializer, MethodScope scope) { + // do nothing by default + } + public void endVisit( + InstanceOfExpression instanceOfExpression, + BlockScope scope) { + // do nothing by default + } + public void endVisit(IntLiteral intLiteral, BlockScope scope) { + // do nothing by default + } + public void endVisit(LabeledStatement labeledStatement, BlockScope scope) { + // do nothing by default + } + public void endVisit(LocalDeclaration localDeclaration, BlockScope scope) { + // do nothing by default + } + public void endVisit(LongLiteral longLiteral, BlockScope scope) { + // do nothing by default + } + public void endVisit(MessageSend messageSend, BlockScope scope) { + // do nothing by default + } + public void endVisit(MethodDeclaration methodDeclaration, ClassScope scope) { + // do nothing by default + } + public void endVisit(StringLiteralConcatenation literal, BlockScope scope) { + // do nothing by default + } + public void endVisit(NullLiteral nullLiteral, BlockScope scope) { + // do nothing by default + } + public void endVisit(OR_OR_Expression or_or_Expression, BlockScope scope) { + // do nothing by default + } + public void endVisit(PostfixExpression postfixExpression, BlockScope scope) { + // do nothing by default + } + public void endVisit(PrefixExpression prefixExpression, BlockScope scope) { + // do nothing by default + } + public void endVisit( + QualifiedAllocationExpression qualifiedAllocationExpression, + BlockScope scope) { + // do nothing by default + } + public void endVisit( + QualifiedNameReference qualifiedNameReference, + BlockScope scope) { + // do nothing by default + } + public void endVisit( + QualifiedSuperReference qualifiedSuperReference, + BlockScope scope) { + // do nothing by default + } + public void endVisit( + QualifiedThisReference qualifiedThisReference, + BlockScope scope) { + // do nothing by default + } + public void endVisit( + QualifiedTypeReference qualifiedTypeReference, + BlockScope scope) { + // do nothing by default + } + public void endVisit( + QualifiedTypeReference qualifiedTypeReference, + ClassScope scope) { + // do nothing by default + } + public void endVisit(ReturnStatement returnStatement, BlockScope scope) { + // do nothing by default + } + public void endVisit( + SingleNameReference singleNameReference, + BlockScope scope) { + // do nothing by default + } + public void endVisit( + SingleTypeReference singleTypeReference, + BlockScope scope) { + // do nothing by default + } + public void endVisit( + SingleTypeReference singleTypeReference, + ClassScope scope) { + // do nothing by default + } + public void endVisit(StringLiteral stringLiteral, BlockScope scope) { + // do nothing by default + } + public void endVisit(SuperReference superReference, BlockScope scope) { + // do nothing by default + } + public void endVisit(SwitchStatement switchStatement, BlockScope scope) { + // do nothing by default + } + public void endVisit( + SynchronizedStatement synchronizedStatement, + BlockScope scope) { + // do nothing by default + } + public void endVisit(ThisReference thisReference, BlockScope scope) { + // do nothing by default + } + public void endVisit(ThrowStatement throwStatement, BlockScope scope) { + // do nothing by default + } + public void endVisit(TrueLiteral trueLiteral, BlockScope scope) { + // do nothing by default + } + public void endVisit(TryStatement tryStatement, BlockScope scope) { + // do nothing by default + } + public void endVisit( + TypeDeclaration localTypeDeclaration, + BlockScope scope) { + // do nothing by default + } + public void endVisit( + TypeDeclaration memberTypeDeclaration, + ClassScope scope) { + // do nothing by default + } + public void endVisit( + TypeDeclaration typeDeclaration, + CompilationUnitScope scope) { + // do nothing by default + } + public void endVisit(UnaryExpression unaryExpression, BlockScope scope) { + // do nothing by default + } + public void endVisit(WhileStatement whileStatement, BlockScope scope) { + // do nothing by default + } + public boolean visit( + AllocationExpression allocationExpression, + BlockScope scope) { + return true; // do nothing by default, keep traversing + // do nothing by default + } + public boolean visit(AND_AND_Expression and_and_Expression, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(JavadocArrayQualifiedTypeReference typeRef, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(JavadocArraySingleTypeReference typeRef, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(JavadocArgumentExpression expression, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(JavadocFieldReference fieldRef, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(JavadocMessageSend messageSend, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(JavadocQualifiedTypeReference typeRef, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(JavadocReturnStatement statement, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(JavadocSingleNameReference argument, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(JavadocSingleTypeReference typeRef, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(Argument argument, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit( + ArrayAllocationExpression arrayAllocationExpression, + BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(ArrayInitializer arrayInitializer, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit( + ArrayQualifiedTypeReference arrayQualifiedTypeReference, + BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit( + ArrayQualifiedTypeReference arrayQualifiedTypeReference, + ClassScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(ArrayReference arrayReference, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(ArrayTypeReference arrayTypeReference, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(ArrayTypeReference arrayTypeReference, ClassScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(Assignment assignment, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(AssertStatement assertStatement, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(BinaryExpression binaryExpression, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(Block block, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(BreakStatement breakStatement, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(CaseStatement caseStatement, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(CastExpression castExpression, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(CharLiteral charLiteral, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(ClassLiteralAccess classLiteral, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(Clinit clinit, ClassScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit( + CompilationUnitDeclaration compilationUnitDeclaration, + CompilationUnitScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(CompoundAssignment compoundAssignment, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit( + ConditionalExpression conditionalExpression, + BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit( + ConstructorDeclaration constructorDeclaration, + ClassScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(ContinueStatement continueStatement, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(DoStatement doStatement, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(DoubleLiteral doubleLiteral, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(EqualExpression equalExpression, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(EmptyStatement emptyStatement, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit( + ExplicitConstructorCall explicitConstructor, + BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit( + ExtendedStringLiteral extendedStringLiteral, + BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(FalseLiteral falseLiteral, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(FieldDeclaration fieldDeclaration, MethodScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(FieldReference fieldReference, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(FloatLiteral floatLiteral, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(ForStatement forStatement, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(IfStatement ifStatement, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(ImportReference importRef, CompilationUnitScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(Initializer initializer, MethodScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit( + InstanceOfExpression instanceOfExpression, + BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(IntLiteral intLiteral, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(LabeledStatement labeledStatement, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(LocalDeclaration localDeclaration, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(LongLiteral longLiteral, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(MessageSend messageSend, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(MethodDeclaration methodDeclaration, ClassScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit( + StringLiteralConcatenation literal, + BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(NullLiteral nullLiteral, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(OR_OR_Expression or_or_Expression, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(PostfixExpression postfixExpression, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(PrefixExpression prefixExpression, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit( + QualifiedAllocationExpression qualifiedAllocationExpression, + BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit( + QualifiedNameReference qualifiedNameReference, + BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit( + QualifiedSuperReference qualifiedSuperReference, + BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit( + QualifiedThisReference qualifiedThisReference, + BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit( + QualifiedTypeReference qualifiedTypeReference, + BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit( + QualifiedTypeReference qualifiedTypeReference, + ClassScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(ReturnStatement returnStatement, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit( + SingleNameReference singleNameReference, + BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit( + SingleTypeReference singleTypeReference, + BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit( + SingleTypeReference singleTypeReference, + ClassScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(StringLiteral stringLiteral, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(SuperReference superReference, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(SwitchStatement switchStatement, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit( + SynchronizedStatement synchronizedStatement, + BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(ThisReference thisReference, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(ThrowStatement throwStatement, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(TrueLiteral trueLiteral, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(TryStatement tryStatement, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit( + TypeDeclaration localTypeDeclaration, + BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit( + TypeDeclaration memberTypeDeclaration, + ClassScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit( + TypeDeclaration typeDeclaration, + CompilationUnitScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(UnaryExpression unaryExpression, BlockScope scope) { + return true; // do nothing by default, keep traversing + } + public boolean visit(WhileStatement whileStatement, BlockScope scope) { + return true; // do nothing by default, keep traversing + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ClassFile.java b/src/java/org/eclipse/jdt/internal/compiler/ClassFile.java new file mode 100644 index 0000000..e575af5 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ClassFile.java @@ -0,0 +1,2621 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler; + +import java.io.*; +import java.util.StringTokenizer; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.core.compiler.IProblem; +import org.eclipse.jdt.internal.compiler.ast.*; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; +import org.eclipse.jdt.internal.compiler.impl.Constant; +import org.eclipse.jdt.internal.compiler.impl.StringConstant; +import org.eclipse.jdt.internal.compiler.lookup.*; +import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; +import org.eclipse.jdt.internal.compiler.util.Util; + +/** + * Represents a class file wrapper on bytes, it is aware of its actual + * type name. + * + * Public APIs are listed below: + * + * byte[] getBytes(); + * Answer the actual bytes of the class file + * + * char[][] getCompoundName(); + * Answer the compound name of the class file. + * For example, {{java}, {util}, {Hashtable}}. + * + * byte[] getReducedBytes(); + * Answer a smaller byte format, which is only contains some structural + * information. Those bytes are decodable with a regular class file reader, + * such as DietClassFileReader + */ +public class ClassFile + implements AttributeNamesConstants, CompilerModifiers, TypeConstants, TypeIds { + public SourceTypeBinding referenceBinding; + public ConstantPool constantPool; + public ClassFile enclosingClassFile; + // used to generate private access methods + public int produceDebugAttributes; + public ReferenceBinding[] innerClassesBindings; + public int numberOfInnerClasses; + public byte[] header; + // the header contains all the bytes till the end of the constant pool + public byte[] contents; + // that collection contains all the remaining bytes of the .class file + public int headerOffset; + public int contentsOffset; + public int constantPoolOffset; + public int methodCountOffset; + public int methodCount; + protected boolean creatingProblemType; + public static final int INITIAL_CONTENTS_SIZE = 400; + public static final int INITIAL_HEADER_SIZE = 1500; + public boolean ownSharedArrays = false; // flag set when header/contents are set to shared arrays + public static final int INNER_CLASSES_SIZE = 5; + public CodeStream codeStream; + protected int problemLine; // used to create line number attributes for problem methods + public long targetJDK; + + /** + * INTERNAL USE-ONLY + * This methods creates a new instance of the receiver. + */ + public ClassFile() { + // default constructor for subclasses + } + + /** + * INTERNAL USE-ONLY + * This methods creates a new instance of the receiver. + * + * @param aType org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding + * @param enclosingClassFile org.eclipse.jdt.internal.compiler.ClassFile + * @param creatingProblemType boolean + */ + public ClassFile( + SourceTypeBinding aType, + ClassFile enclosingClassFile, + boolean creatingProblemType) { + + referenceBinding = aType; + initByteArrays(); + + // generate the magic numbers inside the header + header[headerOffset++] = (byte) (0xCAFEBABEL >> 24); + header[headerOffset++] = (byte) (0xCAFEBABEL >> 16); + header[headerOffset++] = (byte) (0xCAFEBABEL >> 8); + header[headerOffset++] = (byte) (0xCAFEBABEL >> 0); + + this.targetJDK = referenceBinding.scope.environment().options.targetJDK; + header[headerOffset++] = (byte) (this.targetJDK >> 8); // minor high + header[headerOffset++] = (byte) (this.targetJDK >> 0); // minor low + header[headerOffset++] = (byte) (this.targetJDK >> 24); // major high + header[headerOffset++] = (byte) (this.targetJDK >> 16); // major low + + constantPoolOffset = headerOffset; + headerOffset += 2; + constantPool = new ConstantPool(this); + + // Modifier manipulations for classfile + int accessFlags = aType.getAccessFlags(); + if (aType.isPrivate()) { // rewrite private to non-public + accessFlags &= ~AccPublic; + } + if (aType.isProtected()) { // rewrite protected into public + accessFlags |= AccPublic; + } + // clear all bits that are illegal for a class or an interface + accessFlags + &= ~( + AccStrictfp + | AccProtected + | AccPrivate + | AccStatic + | AccSynchronized + | AccNative); + + // set the AccSuper flag (has to be done after clearing AccSynchronized - since same value) + if (aType.isClass()) { + accessFlags |= AccSuper; + } + + this.enclosingClassFile = enclosingClassFile; + // innerclasses get their names computed at code gen time + + // now we continue to generate the bytes inside the contents array + contents[contentsOffset++] = (byte) (accessFlags >> 8); + contents[contentsOffset++] = (byte) accessFlags; + int classNameIndex = constantPool.literalIndex(aType); + contents[contentsOffset++] = (byte) (classNameIndex >> 8); + contents[contentsOffset++] = (byte) classNameIndex; + int superclassNameIndex; + if (aType.isInterface()) { + superclassNameIndex = constantPool.literalIndexForJavaLangObject(); + } else { + superclassNameIndex = + (aType.superclass == null ? 0 : constantPool.literalIndex(aType.superclass)); + } + contents[contentsOffset++] = (byte) (superclassNameIndex >> 8); + contents[contentsOffset++] = (byte) superclassNameIndex; + ReferenceBinding[] superInterfacesBinding = aType.superInterfaces(); + int interfacesCount = superInterfacesBinding.length; + contents[contentsOffset++] = (byte) (interfacesCount >> 8); + contents[contentsOffset++] = (byte) interfacesCount; + for (int i = 0; i < interfacesCount; i++) { + int interfaceIndex = constantPool.literalIndex(superInterfacesBinding[i]); + contents[contentsOffset++] = (byte) (interfaceIndex >> 8); + contents[contentsOffset++] = (byte) interfaceIndex; + } + produceDebugAttributes = referenceBinding.scope.environment().options.produceDebugAttributes; + innerClassesBindings = new ReferenceBinding[INNER_CLASSES_SIZE]; + this.creatingProblemType = creatingProblemType; + codeStream = new CodeStream(this); + + // retrieve the enclosing one guaranteed to be the one matching the propagated flow info + // 1FF9ZBU: LFCOM:ALL - Local variable attributes busted (Sanity check) + ClassFile outermostClassFile = this.outerMostEnclosingClassFile(); + if (this == outermostClassFile) { + codeStream.maxFieldCount = aType.scope.referenceType().maxFieldCount; + } else { + codeStream.maxFieldCount = outermostClassFile.codeStream.maxFieldCount; + } + } + + /** + * INTERNAL USE-ONLY + * Generate the byte for a problem method info that correspond to a boggus method. + * + * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration + * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding + */ + public void addAbstractMethod( + AbstractMethodDeclaration method, + MethodBinding methodBinding) { + + // force the modifiers to be public and abstract + methodBinding.modifiers = AccPublic | AccAbstract; + + this.generateMethodInfoHeader(methodBinding); + int methodAttributeOffset = this.contentsOffset; + int attributeNumber = this.generateMethodInfoAttribute(methodBinding); + this.completeMethodInfo(methodAttributeOffset, attributeNumber); + } + + /** + * INTERNAL USE-ONLY + * This methods generate all the attributes for the receiver. + * For a class they could be: + * - source file attribute + * - inner classes attribute + * - deprecated attribute + */ + public void addAttributes() { + // update the method count + contents[methodCountOffset++] = (byte) (methodCount >> 8); + contents[methodCountOffset] = (byte) methodCount; + + int attributeNumber = 0; + // leave two bytes for the number of attributes and store the current offset + int attributeOffset = contentsOffset; + contentsOffset += 2; + + // source attribute + if ((produceDebugAttributes & CompilerOptions.Source) != 0) { + String fullFileName = + new String(referenceBinding.scope.referenceCompilationUnit().getFileName()); + fullFileName = fullFileName.replace('\\', '/'); + int lastIndex = fullFileName.lastIndexOf('/'); + if (lastIndex != -1) { + fullFileName = fullFileName.substring(lastIndex + 1, fullFileName.length()); + } + // check that there is enough space to write all the bytes for the field info corresponding + // to the @fieldBinding + if (contentsOffset + 8 >= contents.length) { + resizeContents(8); + } + int sourceAttributeNameIndex = + constantPool.literalIndex(AttributeNamesConstants.SourceName); + contents[contentsOffset++] = (byte) (sourceAttributeNameIndex >> 8); + contents[contentsOffset++] = (byte) sourceAttributeNameIndex; + // The length of a source file attribute is 2. This is a fixed-length + // attribute + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 2; + // write the source file name + int fileNameIndex = constantPool.literalIndex(fullFileName.toCharArray()); + contents[contentsOffset++] = (byte) (fileNameIndex >> 8); + contents[contentsOffset++] = (byte) fileNameIndex; + attributeNumber++; + } + // Deprecated attribute + if (referenceBinding.isDeprecated()) { + // check that there is enough space to write all the bytes for the field info corresponding + // to the @fieldBinding + if (contentsOffset + 6 >= contents.length) { + resizeContents(6); + } + int deprecatedAttributeNameIndex = + constantPool.literalIndex(AttributeNamesConstants.DeprecatedName); + contents[contentsOffset++] = (byte) (deprecatedAttributeNameIndex >> 8); + contents[contentsOffset++] = (byte) deprecatedAttributeNameIndex; + // the length of a deprecated attribute is equals to 0 + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + attributeNumber++; + } + // Inner class attribute + if (numberOfInnerClasses != 0) { + // Generate the inner class attribute + int exSize = 8 * numberOfInnerClasses + 8; + if (exSize + contentsOffset >= this.contents.length) { + resizeContents(exSize); + } + // Now we now the size of the attribute and the number of entries + // attribute name + int attributeNameIndex = + constantPool.literalIndex(AttributeNamesConstants.InnerClassName); + contents[contentsOffset++] = (byte) (attributeNameIndex >> 8); + contents[contentsOffset++] = (byte) attributeNameIndex; + int value = (numberOfInnerClasses << 3) + 2; + contents[contentsOffset++] = (byte) (value >> 24); + contents[contentsOffset++] = (byte) (value >> 16); + contents[contentsOffset++] = (byte) (value >> 8); + contents[contentsOffset++] = (byte) value; + contents[contentsOffset++] = (byte) (numberOfInnerClasses >> 8); + contents[contentsOffset++] = (byte) numberOfInnerClasses; + for (int i = 0; i < numberOfInnerClasses; i++) { + ReferenceBinding innerClass = innerClassesBindings[i]; + int accessFlags = innerClass.getAccessFlags(); + int innerClassIndex = constantPool.literalIndex(innerClass); + // inner class index + contents[contentsOffset++] = (byte) (innerClassIndex >> 8); + contents[contentsOffset++] = (byte) innerClassIndex; + // outer class index: anonymous and local have no outer class index + if (innerClass.isMemberType()) { + // member or member of local + int outerClassIndex = constantPool.literalIndex(innerClass.enclosingType()); + contents[contentsOffset++] = (byte) (outerClassIndex >> 8); + contents[contentsOffset++] = (byte) outerClassIndex; + } else { + // equals to 0 if the innerClass is not a member type + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + } + // name index + if (!innerClass.isAnonymousType()) { + int nameIndex = constantPool.literalIndex(innerClass.sourceName()); + contents[contentsOffset++] = (byte) (nameIndex >> 8); + contents[contentsOffset++] = (byte) nameIndex; + } else { + // equals to 0 if the innerClass is an anonymous type + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + } + // access flag + if (innerClass.isAnonymousType()) { + accessFlags |= AccPrivate; + } else + if (innerClass.isLocalType() && !innerClass.isMemberType()) { + accessFlags |= AccPrivate; + } + contents[contentsOffset++] = (byte) (accessFlags >> 8); + contents[contentsOffset++] = (byte) accessFlags; + } + attributeNumber++; + } + // update the number of attributes + if (attributeOffset + 2 >= this.contents.length) { + resizeContents(2); + } + contents[attributeOffset++] = (byte) (attributeNumber >> 8); + contents[attributeOffset] = (byte) attributeNumber; + + // resynchronize all offsets of the classfile + header = constantPool.poolContent; + headerOffset = constantPool.currentOffset; + int constantPoolCount = constantPool.currentIndex; + header[constantPoolOffset++] = (byte) (constantPoolCount >> 8); + header[constantPoolOffset] = (byte) constantPoolCount; + } + + /** + * INTERNAL USE-ONLY + * This methods generate all the default abstract method infos that correpond to + * the abstract methods inherited from superinterfaces. + */ + public void addDefaultAbstractMethods() { // default abstract methods + MethodBinding[] defaultAbstractMethods = + referenceBinding.getDefaultAbstractMethods(); + for (int i = 0, max = defaultAbstractMethods.length; i < max; i++) { + generateMethodInfoHeader(defaultAbstractMethods[i]); + int methodAttributeOffset = contentsOffset; + int attributeNumber = generateMethodInfoAttribute(defaultAbstractMethods[i]); + completeMethodInfo(methodAttributeOffset, attributeNumber); + } + } + + /** + * INTERNAL USE-ONLY + * This methods generates the bytes for the field binding passed like a parameter + * @param fieldBinding org.eclipse.jdt.internal.compiler.lookup.FieldBinding + */ + public void addFieldInfo(FieldBinding fieldBinding) { + int attributeNumber = 0; + // check that there is enough space to write all the bytes for the field info corresponding + // to the @fieldBinding + if (contentsOffset + 30 >= contents.length) { + resizeContents(30); + } + // Generate two attribute: constantValueAttribute and SyntheticAttribute + // Now we can generate all entries into the byte array + // First the accessFlags + int accessFlags = fieldBinding.getAccessFlags(); + contents[contentsOffset++] = (byte) (accessFlags >> 8); + contents[contentsOffset++] = (byte) accessFlags; + // Then the nameIndex + int nameIndex = constantPool.literalIndex(fieldBinding.name); + contents[contentsOffset++] = (byte) (nameIndex >> 8); + contents[contentsOffset++] = (byte) nameIndex; + // Then the descriptorIndex + int descriptorIndex = constantPool.literalIndex(fieldBinding.type.signature()); + contents[contentsOffset++] = (byte) (descriptorIndex >> 8); + contents[contentsOffset++] = (byte) descriptorIndex; + // leave some space for the number of attributes + int fieldAttributeOffset = contentsOffset; + contentsOffset += 2; + // 4.7.2 only static constant fields get a ConstantAttribute + if (fieldBinding.constant != Constant.NotAConstant){ + // Now we generate the constant attribute corresponding to the fieldBinding + int constantValueNameIndex = + constantPool.literalIndex(AttributeNamesConstants.ConstantValueName); + contents[contentsOffset++] = (byte) (constantValueNameIndex >> 8); + contents[contentsOffset++] = (byte) constantValueNameIndex; + // The attribute length = 2 in case of a constantValue attribute + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 2; + attributeNumber++; + // Need to add the constant_value_index + switch (fieldBinding.constant.typeID()) { + case T_boolean : + int booleanValueIndex = + constantPool.literalIndex(fieldBinding.constant.booleanValue() ? 1 : 0); + contents[contentsOffset++] = (byte) (booleanValueIndex >> 8); + contents[contentsOffset++] = (byte) booleanValueIndex; + break; + case T_byte : + case T_char : + case T_int : + case T_short : + int integerValueIndex = + constantPool.literalIndex(fieldBinding.constant.intValue()); + contents[contentsOffset++] = (byte) (integerValueIndex >> 8); + contents[contentsOffset++] = (byte) integerValueIndex; + break; + case T_float : + int floatValueIndex = + constantPool.literalIndex(fieldBinding.constant.floatValue()); + contents[contentsOffset++] = (byte) (floatValueIndex >> 8); + contents[contentsOffset++] = (byte) floatValueIndex; + break; + case T_double : + int doubleValueIndex = + constantPool.literalIndex(fieldBinding.constant.doubleValue()); + contents[contentsOffset++] = (byte) (doubleValueIndex >> 8); + contents[contentsOffset++] = (byte) doubleValueIndex; + break; + case T_long : + int longValueIndex = + constantPool.literalIndex(fieldBinding.constant.longValue()); + contents[contentsOffset++] = (byte) (longValueIndex >> 8); + contents[contentsOffset++] = (byte) longValueIndex; + break; + case T_String : + int stringValueIndex = + constantPool.literalIndex( + ((StringConstant) fieldBinding.constant).stringValue()); + if (stringValueIndex == -1) { + if (!creatingProblemType) { + // report an error and abort: will lead to a problem type classfile creation + TypeDeclaration typeDeclaration = referenceBinding.scope.referenceContext; + FieldDeclaration[] fieldDecls = typeDeclaration.fields; + for (int i = 0, max = fieldDecls.length; i < max; i++) { + if (fieldDecls[i].binding == fieldBinding) { + // problem should abort + typeDeclaration.scope.problemReporter().stringConstantIsExceedingUtf8Limit( + fieldDecls[i]); + } + } + } else { + // already inside a problem type creation : no constant for this field + contentsOffset = fieldAttributeOffset + 2; + // +2 is necessary to keep the two byte space for the attribute number + attributeNumber--; + } + } else { + contents[contentsOffset++] = (byte) (stringValueIndex >> 8); + contents[contentsOffset++] = (byte) stringValueIndex; + } + } + } + if (fieldBinding.isSynthetic()) { + int syntheticAttributeNameIndex = + constantPool.literalIndex(AttributeNamesConstants.SyntheticName); + contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8); + contents[contentsOffset++] = (byte) syntheticAttributeNameIndex; + // the length of a synthetic attribute is equals to 0 + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + attributeNumber++; + } + if (fieldBinding.isDeprecated()) { + int deprecatedAttributeNameIndex = + constantPool.literalIndex(AttributeNamesConstants.DeprecatedName); + contents[contentsOffset++] = (byte) (deprecatedAttributeNameIndex >> 8); + contents[contentsOffset++] = (byte) deprecatedAttributeNameIndex; + // the length of a deprecated attribute is equals to 0 + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + attributeNumber++; + } + contents[fieldAttributeOffset++] = (byte) (attributeNumber >> 8); + contents[fieldAttributeOffset] = (byte) attributeNumber; + } + + /** + * INTERNAL USE-ONLY + * This methods generate all the fields infos for the receiver. + * This includes: + * - a field info for each defined field of that class + * - a field info for each synthetic field (e.g. this$0) + */ + public void addFieldInfos() { + SourceTypeBinding currentBinding = referenceBinding; + FieldBinding[] syntheticFields = currentBinding.syntheticFields(); + int fieldCount = + currentBinding.fieldCount() + + (syntheticFields == null ? 0 : syntheticFields.length); + + // write the number of fields + if (fieldCount > 0xFFFF) { + referenceBinding.scope.problemReporter().tooManyFields(referenceBinding.scope.referenceType()); + } + contents[contentsOffset++] = (byte) (fieldCount >> 8); + contents[contentsOffset++] = (byte) fieldCount; + + FieldBinding[] fieldBindings = currentBinding.fields(); + for (int i = 0, max = fieldBindings.length; i < max; i++) { + addFieldInfo(fieldBindings[i]); + } + if (syntheticFields != null) { + for (int i = 0, max = syntheticFields.length; i < max; i++) { + addFieldInfo(syntheticFields[i]); + } + } + } + + /** + * INTERNAL USE-ONLY + * This methods stores the bindings for each inner class. They will be used to know which entries + * have to be generated for the inner classes attributes. + * @param refBinding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding + */ + public void addInnerClasses(ReferenceBinding refBinding) { + // check first if that reference binding is there + for (int i = 0; i < numberOfInnerClasses; i++) { + if (innerClassesBindings[i] == refBinding) + return; + } + int length = innerClassesBindings.length; + if (numberOfInnerClasses == length) { + System.arraycopy( + innerClassesBindings, + 0, + innerClassesBindings = new ReferenceBinding[length * 2], + 0, + length); + } + innerClassesBindings[numberOfInnerClasses++] = refBinding; + } + + /** + * INTERNAL USE-ONLY + * Generate the byte for a problem clinit method info that correspond to a boggus method. + * + * @param problems org.eclipse.jdt.internal.compiler.problem.Problem[] + */ + public void addProblemClinit(IProblem[] problems) { + generateMethodInfoHeaderForClinit(); + // leave two spaces for the number of attributes + contentsOffset -= 2; + int attributeOffset = contentsOffset; + contentsOffset += 2; + int attributeNumber = 0; + + int codeAttributeOffset = contentsOffset; + generateCodeAttributeHeader(); + codeStream.resetForProblemClinit(this); + String problemString = "" ; //$NON-NLS-1$ + if (problems != null) { + int max = problems.length; + StringBuffer buffer = new StringBuffer(25); + int count = 0; + for (int i = 0; i < max; i++) { + IProblem problem = problems[i]; + if ((problem != null) && (problem.isError())) { + buffer.append("\t" +problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$ + count++; + if (problemLine == 0) { + problemLine = problem.getSourceLineNumber(); + } + problems[i] = null; + } + } // insert the top line afterwards, once knowing how many problems we have to consider + if (count > 1) { + buffer.insert(0, Util.bind("compilation.unresolvedProblems" )); //$NON-NLS-1$ + } else { + buffer.insert(0, Util.bind("compilation.unresolvedProblem" )); //$NON-NLS-1$ + } + problemString = buffer.toString(); + } + + // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "") + codeStream.generateCodeAttributeForProblemMethod(problemString); + attributeNumber++; // code attribute + completeCodeAttributeForClinit( + codeAttributeOffset, + referenceBinding + .scope + .referenceCompilationUnit() + .compilationResult + .lineSeparatorPositions); + contents[attributeOffset++] = (byte) (attributeNumber >> 8); + contents[attributeOffset] = (byte) attributeNumber; + } + + /** + * INTERNAL USE-ONLY + * Generate the byte for a problem method info that correspond to a boggus constructor. + * + * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration + * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding + * @param problems org.eclipse.jdt.internal.compiler.problem.Problem[] + */ + public void addProblemConstructor( + AbstractMethodDeclaration method, + MethodBinding methodBinding, + IProblem[] problems) { + + // always clear the strictfp/native/abstract bit for a problem method + generateMethodInfoHeader(methodBinding, methodBinding.modifiers & ~(AccStrictfp | AccNative | AccAbstract)); + int methodAttributeOffset = contentsOffset; + int attributeNumber = generateMethodInfoAttribute(methodBinding); + + // Code attribute + attributeNumber++; + int codeAttributeOffset = contentsOffset; + generateCodeAttributeHeader(); + codeStream.reset(method, this); + String problemString = "" ; //$NON-NLS-1$ + if (problems != null) { + int max = problems.length; + StringBuffer buffer = new StringBuffer(25); + int count = 0; + for (int i = 0; i < max; i++) { + IProblem problem = problems[i]; + if ((problem != null) && (problem.isError())) { + buffer.append("\t" +problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$ + count++; + if (problemLine == 0) { + problemLine = problem.getSourceLineNumber(); + } + } + } // insert the top line afterwards, once knowing how many problems we have to consider + if (count > 1) { + buffer.insert(0, Util.bind("compilation.unresolvedProblems" )); //$NON-NLS-1$ + } else { + buffer.insert(0, Util.bind("compilation.unresolvedProblem" )); //$NON-NLS-1$ + } + problemString = buffer.toString(); + } + + // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "") + codeStream.generateCodeAttributeForProblemMethod(problemString); + completeCodeAttributeForProblemMethod( + method, + methodBinding, + codeAttributeOffset, + ((SourceTypeBinding) methodBinding.declaringClass) + .scope + .referenceCompilationUnit() + .compilationResult + .lineSeparatorPositions); + completeMethodInfo(methodAttributeOffset, attributeNumber); + } + + /** + * INTERNAL USE-ONLY + * Generate the byte for a problem method info that correspond to a boggus constructor. + * Reset the position inside the contents byte array to the savedOffset. + * + * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration + * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding + * @param problems org.eclipse.jdt.internal.compiler.problem.Problem[] + * @param savedOffset int + */ + public void addProblemConstructor( + AbstractMethodDeclaration method, + MethodBinding methodBinding, + IProblem[] problems, + int savedOffset) { + // we need to move back the contentsOffset to the value at the beginning of the method + contentsOffset = savedOffset; + methodCount--; // we need to remove the method that causes the problem + addProblemConstructor(method, methodBinding, problems); + } + + /** + * INTERNAL USE-ONLY + * Generate the byte for a problem method info that correspond to a boggus method. + * + * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration + * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding + * @param problems org.eclipse.jdt.internal.compiler.problem.Problem[] + */ + public void addProblemMethod( + AbstractMethodDeclaration method, + MethodBinding methodBinding, + IProblem[] problems) { + if (methodBinding.isAbstract() && methodBinding.declaringClass.isInterface()) { + method.abort(ProblemSeverities.AbortType, null); + } + // always clear the strictfp/native/abstract bit for a problem method + generateMethodInfoHeader(methodBinding, methodBinding.modifiers & ~(AccStrictfp | AccNative | AccAbstract)); + int methodAttributeOffset = contentsOffset; + int attributeNumber = generateMethodInfoAttribute(methodBinding); + + // Code attribute + attributeNumber++; + + int codeAttributeOffset = contentsOffset; + generateCodeAttributeHeader(); + codeStream.reset(method, this); + String problemString = "" ; //$NON-NLS-1$ + if (problems != null) { + int max = problems.length; + StringBuffer buffer = new StringBuffer(25); + int count = 0; + for (int i = 0; i < max; i++) { + IProblem problem = problems[i]; + if ((problem != null) + && (problem.isError()) + && (problem.getSourceStart() >= method.declarationSourceStart) + && (problem.getSourceEnd() <= method.declarationSourceEnd)) { + buffer.append("\t" +problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$ + count++; + if (problemLine == 0) { + problemLine = problem.getSourceLineNumber(); + } + problems[i] = null; + } + } // insert the top line afterwards, once knowing how many problems we have to consider + if (count > 1) { + buffer.insert(0, Util.bind("compilation.unresolvedProblems" )); //$NON-NLS-1$ + } else { + buffer.insert(0, Util.bind("compilation.unresolvedProblem" )); //$NON-NLS-1$ + } + problemString = buffer.toString(); + } + + // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "") + codeStream.generateCodeAttributeForProblemMethod(problemString); + completeCodeAttributeForProblemMethod( + method, + methodBinding, + codeAttributeOffset, + ((SourceTypeBinding) methodBinding.declaringClass) + .scope + .referenceCompilationUnit() + .compilationResult + .lineSeparatorPositions); + completeMethodInfo(methodAttributeOffset, attributeNumber); + } + + /** + * INTERNAL USE-ONLY + * Generate the byte for a problem method info that correspond to a boggus method. + * Reset the position inside the contents byte array to the savedOffset. + * + * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration + * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding + * @param problems org.eclipse.jdt.internal.compiler.problem.Problem[] + * @param savedOffset int + */ + public void addProblemMethod( + AbstractMethodDeclaration method, + MethodBinding methodBinding, + IProblem[] problems, + int savedOffset) { + // we need to move back the contentsOffset to the value at the beginning of the method + contentsOffset = savedOffset; + methodCount--; // we need to remove the method that causes the problem + addProblemMethod(method, methodBinding, problems); + } + + /** + * INTERNAL USE-ONLY + * Generate the byte for all the special method infos. + * They are: + * - synthetic access methods + * - default abstract methods + */ + public void addSpecialMethods() { + // add all methods (default abstract methods and synthetic) + + // default abstract methods + SourceTypeBinding currentBinding = referenceBinding; + MethodBinding[] defaultAbstractMethods = + currentBinding.getDefaultAbstractMethods(); + for (int i = 0, max = defaultAbstractMethods.length; i < max; i++) { + generateMethodInfoHeader(defaultAbstractMethods[i]); + int methodAttributeOffset = contentsOffset; + int attributeNumber = generateMethodInfoAttribute(defaultAbstractMethods[i]); + completeMethodInfo(methodAttributeOffset, attributeNumber); + } + // add synthetic methods infos + SyntheticAccessMethodBinding[] syntheticAccessMethods = + currentBinding.syntheticAccessMethods(); + if (syntheticAccessMethods != null) { + for (int i = 0, max = syntheticAccessMethods.length; i < max; i++) { + SyntheticAccessMethodBinding accessMethodBinding = syntheticAccessMethods[i]; + switch (accessMethodBinding.accessType) { + case SyntheticAccessMethodBinding.FieldReadAccess : + // generate a method info to emulate an reading access to + // a non-accessible field + addSyntheticFieldReadAccessMethod(syntheticAccessMethods[i]); + break; + case SyntheticAccessMethodBinding.FieldWriteAccess : + // generate a method info to emulate an writing access to + // a non-accessible field + addSyntheticFieldWriteAccessMethod(syntheticAccessMethods[i]); + break; + case SyntheticAccessMethodBinding.MethodAccess : + case SyntheticAccessMethodBinding.SuperMethodAccess : + // generate a method info to emulate an access to a non-accessible method / super-method + addSyntheticMethodAccessMethod(syntheticAccessMethods[i]); + break; + case SyntheticAccessMethodBinding.ConstructorAccess : + // generate a method info to emulate an access to a non-accessible constructor + addSyntheticConstructorAccessMethod(syntheticAccessMethods[i]); + } + } + } + } + + /** + * INTERNAL USE-ONLY + * Generate the byte for problem method infos that correspond to missing abstract methods. + * http://dev.eclipse.org/bugs/show_bug.cgi?id=3179 + * + * @param methodDeclarations Array of all missing abstract methods + */ + public void generateMissingAbstractMethods(MethodDeclaration[] methodDeclarations, CompilationResult compilationResult) { + if (methodDeclarations != null) { + for (int i = 0, max = methodDeclarations.length; i < max; i++) { + MethodDeclaration methodDeclaration = methodDeclarations[i]; + MethodBinding methodBinding = methodDeclaration.binding; + String readableName = new String(methodBinding.readableName()); + IProblem[] problems = compilationResult.problems; + int problemsCount = compilationResult.problemCount; + for (int j = 0; j < problemsCount; j++) { + IProblem problem = problems[j]; + if (problem != null + && problem.getID() == IProblem.AbstractMethodMustBeImplemented + && problem.getMessage().indexOf(readableName) != -1) { + // we found a match + addMissingAbstractProblemMethod(methodDeclaration, methodBinding, problem, compilationResult); + } + } + } + } + } + + private void addMissingAbstractProblemMethod(MethodDeclaration methodDeclaration, MethodBinding methodBinding, IProblem problem, CompilationResult compilationResult) { + // always clear the strictfp/native/abstract bit for a problem method + generateMethodInfoHeader(methodBinding, methodBinding.modifiers & ~(AccStrictfp | AccNative | AccAbstract)); + int methodAttributeOffset = contentsOffset; + int attributeNumber = generateMethodInfoAttribute(methodBinding); + + // Code attribute + attributeNumber++; + + int codeAttributeOffset = contentsOffset; + generateCodeAttributeHeader(); + StringBuffer buffer = new StringBuffer(25); + buffer.append("\t" + problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$ + buffer.insert(0, Util.bind("compilation.unresolvedProblem" )); //$NON-NLS-1$ + String problemString = buffer.toString(); + this.problemLine = problem.getSourceLineNumber(); + + codeStream.init(this); + codeStream.preserveUnusedLocals = true; + codeStream.initializeMaxLocals(methodBinding); + + // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "") + codeStream.generateCodeAttributeForProblemMethod(problemString); + + completeCodeAttributeForMissingAbstractProblemMethod( + methodBinding, + codeAttributeOffset, + compilationResult.lineSeparatorPositions); + + completeMethodInfo(methodAttributeOffset, attributeNumber); + } + + /** + * + */ + public void completeCodeAttributeForMissingAbstractProblemMethod( + MethodBinding binding, + int codeAttributeOffset, + int[] startLineIndexes) { + // reinitialize the localContents with the byte modified by the code stream + this.contents = codeStream.bCodeStream; + int localContentsOffset = codeStream.classFileOffset; + // codeAttributeOffset is the position inside localContents byte array before we started to write// any information about the codeAttribute// That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset// to get the right position, 6 for the max_stack etc... + int max_stack = codeStream.stackMax; + this.contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8); + this.contents[codeAttributeOffset + 7] = (byte) max_stack; + int max_locals = codeStream.maxLocals; + this.contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8); + this.contents[codeAttributeOffset + 9] = (byte) max_locals; + int code_length = codeStream.position; + this.contents[codeAttributeOffset + 10] = (byte) (code_length >> 24); + this.contents[codeAttributeOffset + 11] = (byte) (code_length >> 16); + this.contents[codeAttributeOffset + 12] = (byte) (code_length >> 8); + this.contents[codeAttributeOffset + 13] = (byte) code_length; + // write the exception table + if (localContentsOffset + 50 >= this.contents.length) { + resizeContents(50); + } + this.contents[localContentsOffset++] = 0; + this.contents[localContentsOffset++] = 0; + // debug attributes + int codeAttributeAttributeOffset = localContentsOffset; + int attributeNumber = 0; // leave two bytes for the attribute_length + localContentsOffset += 2; // first we handle the linenumber attribute + + if (codeStream.generateLineNumberAttributes) { + /* Create and add the line number attribute (used for debugging) + * Build the pairs of: + * (bytecodePC lineNumber) + * according to the table of start line indexes and the pcToSourceMap table + * contained into the codestream + */ + int lineNumberNameIndex = + constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName); + this.contents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8); + this.contents[localContentsOffset++] = (byte) lineNumberNameIndex; + this.contents[localContentsOffset++] = 0; + this.contents[localContentsOffset++] = 0; + this.contents[localContentsOffset++] = 0; + this.contents[localContentsOffset++] = 6; + this.contents[localContentsOffset++] = 0; + this.contents[localContentsOffset++] = 1; + if (problemLine == 0) { + problemLine = searchLineNumber(startLineIndexes, binding.sourceStart()); + } + // first entry at pc = 0 + this.contents[localContentsOffset++] = 0; + this.contents[localContentsOffset++] = 0; + this.contents[localContentsOffset++] = (byte) (problemLine >> 8); + this.contents[localContentsOffset++] = (byte) problemLine; + // now we change the size of the line number attribute + attributeNumber++; + } + + // then we do the local variable attribute + // update the number of attributes// ensure first that there is enough space available inside the localContents array + if (codeAttributeAttributeOffset + 2 >= this.contents.length) { + resizeContents(2); + } + this.contents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8); + this.contents[codeAttributeAttributeOffset] = (byte) attributeNumber; + // update the attribute length + int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6); + this.contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24); + this.contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16); + this.contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8); + this.contents[codeAttributeOffset + 5] = (byte) codeAttributeLength; + contentsOffset = localContentsOffset; + } + + /** + * INTERNAL USE-ONLY + * Generate the byte for a problem method info that correspond to a synthetic method that + * generate an access to a private constructor. + * + * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding + */ + public void addSyntheticConstructorAccessMethod(SyntheticAccessMethodBinding methodBinding) { + generateMethodInfoHeader(methodBinding); + // We know that we won't get more than 2 attribute: the code attribute + synthetic attribute + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 2; + // Code attribute + int codeAttributeOffset = contentsOffset; + generateCodeAttributeHeader(); + codeStream.init(this); + codeStream.generateSyntheticBodyForConstructorAccess(methodBinding); + completeCodeAttributeForSyntheticAccessMethod( + methodBinding, + codeAttributeOffset, + ((SourceTypeBinding) methodBinding.declaringClass) + .scope + .referenceCompilationUnit() + .compilationResult + .lineSeparatorPositions); + // add the synthetic attribute + int syntheticAttributeNameIndex = + constantPool.literalIndex(AttributeNamesConstants.SyntheticName); + contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8); + contents[contentsOffset++] = (byte) syntheticAttributeNameIndex; + // the length of a synthetic attribute is equals to 0 + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + } + + /** + * INTERNAL USE-ONLY + * Generate the byte for a problem method info that correspond to a synthetic method that + * generate an read access to a private field. + * + * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding + */ + public void addSyntheticFieldReadAccessMethod(SyntheticAccessMethodBinding methodBinding) { + generateMethodInfoHeader(methodBinding); + // We know that we won't get more than 2 attribute: the code attribute + synthetic attribute + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 2; + // Code attribute + int codeAttributeOffset = contentsOffset; + generateCodeAttributeHeader(); + codeStream.init(this); + codeStream.generateSyntheticBodyForFieldReadAccess(methodBinding); + completeCodeAttributeForSyntheticAccessMethod( + methodBinding, + codeAttributeOffset, + ((SourceTypeBinding) methodBinding.declaringClass) + .scope + .referenceCompilationUnit() + .compilationResult + .lineSeparatorPositions); + // add the synthetic attribute + int syntheticAttributeNameIndex = + constantPool.literalIndex(AttributeNamesConstants.SyntheticName); + contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8); + contents[contentsOffset++] = (byte) syntheticAttributeNameIndex; + // the length of a synthetic attribute is equals to 0 + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + } + + /** + * INTERNAL USE-ONLY + * Generate the byte for a problem method info that correspond to a synthetic method that + * generate an write access to a private field. + * + * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding + */ + public void addSyntheticFieldWriteAccessMethod(SyntheticAccessMethodBinding methodBinding) { + generateMethodInfoHeader(methodBinding); + // We know that we won't get more than 2 attribute: the code attribute + synthetic attribute + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 2; + // Code attribute + int codeAttributeOffset = contentsOffset; + generateCodeAttributeHeader(); + codeStream.init(this); + codeStream.generateSyntheticBodyForFieldWriteAccess(methodBinding); + completeCodeAttributeForSyntheticAccessMethod( + methodBinding, + codeAttributeOffset, + ((SourceTypeBinding) methodBinding.declaringClass) + .scope + .referenceCompilationUnit() + .compilationResult + .lineSeparatorPositions); + // add the synthetic attribute + int syntheticAttributeNameIndex = + constantPool.literalIndex(AttributeNamesConstants.SyntheticName); + contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8); + contents[contentsOffset++] = (byte) syntheticAttributeNameIndex; + // the length of a synthetic attribute is equals to 0 + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + } + + /** + * INTERNAL USE-ONLY + * Generate the byte for a problem method info that correspond to a synthetic method that + * generate an access to a private method. + * + * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding + */ + public void addSyntheticMethodAccessMethod(SyntheticAccessMethodBinding methodBinding) { + generateMethodInfoHeader(methodBinding); + // We know that we won't get more than 2 attribute: the code attribute + synthetic attribute + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 2; + // Code attribute + int codeAttributeOffset = contentsOffset; + generateCodeAttributeHeader(); + codeStream.init(this); + codeStream.generateSyntheticBodyForMethodAccess(methodBinding); + completeCodeAttributeForSyntheticAccessMethod( + methodBinding, + codeAttributeOffset, + ((SourceTypeBinding) methodBinding.declaringClass) + .scope + .referenceCompilationUnit() + .compilationResult + .lineSeparatorPositions); + // add the synthetic attribute + int syntheticAttributeNameIndex = + constantPool.literalIndex(AttributeNamesConstants.SyntheticName); + contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8); + contents[contentsOffset++] = (byte) syntheticAttributeNameIndex; + // the length of a synthetic attribute is equals to 0 + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + } + + /** + * INTERNAL USE-ONLY + * 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; + // 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 + if (outputPath.endsWith(fileSeparator)) { + outputPath = outputPath.substring(0, outputPath.length() - 1); + } + f = new File(outputPath); + if (f.exists()) { + if (!f.isDirectory()) { + System.out.println(Util.bind("output.isFile" , f.getAbsolutePath())); //$NON-NLS-1$ + throw new IOException(Util.bind("output.isFileNotDirectory" )); //$NON-NLS-1$ + } + } else { + // we have to create that directory + if (!f.mkdirs()) { + System.out.println(Util.bind("output.dirName" , f.getAbsolutePath())); //$NON-NLS-1$ + throw new IOException(Util.bind("output.notValidAll" )); //$NON-NLS-1$ + } + } + 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()); + if (f.exists()) { + // The outDir already exists, so we proceed the next entry + // System.out.println("outDir: " + outDir + " already exists."); + } else { + // Need to add the outDir + if (!f.mkdir()) { + System.out.println(Util.bind("output.fileName" , f.getName())); //$NON-NLS-1$ + throw new IOException(Util.bind("output.notValid" )); //$NON-NLS-1$ + } + } + token = tokenizer.nextToken(); + } + // token contains the last one + return outDir.append(token).toString(); + } + + /** + * INTERNAL USE-ONLY + * That method completes the creation of the code attribute by setting + * - the attribute_length + * - max_stack + * - max_locals + * - code_length + * - exception table + * - and debug attributes if necessary. + * + * @param codeAttributeOffset int + */ + public void completeCodeAttribute(int codeAttributeOffset) { + // reinitialize the localContents with the byte modified by the code stream + this.contents = codeStream.bCodeStream; + int localContentsOffset = codeStream.classFileOffset; + // codeAttributeOffset is the position inside localContents byte array before we started to write + // any information about the codeAttribute + // That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset + // to get the right position, 6 for the max_stack etc... + int code_length = codeStream.position; + if (code_length > 65535) { + codeStream.methodDeclaration.scope.problemReporter().bytecodeExceeds64KLimit( + codeStream.methodDeclaration); + } + if (localContentsOffset + 20 >= this.contents.length) { + resizeContents(20); + } + int max_stack = codeStream.stackMax; + this.contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8); + this.contents[codeAttributeOffset + 7] = (byte) max_stack; + int max_locals = codeStream.maxLocals; + this.contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8); + this.contents[codeAttributeOffset + 9] = (byte) max_locals; + this.contents[codeAttributeOffset + 10] = (byte) (code_length >> 24); + this.contents[codeAttributeOffset + 11] = (byte) (code_length >> 16); + this.contents[codeAttributeOffset + 12] = (byte) (code_length >> 8); + this.contents[codeAttributeOffset + 13] = (byte) code_length; + + // write the exception table + int exceptionHandlersNumber = codeStream.exceptionHandlersNumber; + ExceptionLabel[] exceptionHandlers = codeStream.exceptionHandlers; + int exSize = exceptionHandlersNumber * 8 + 2; + if (exSize + localContentsOffset >= this.contents.length) { + resizeContents(exSize); + } + // there is no exception table, so we need to offset by 2 the current offset and move + // on the attribute generation + this.contents[localContentsOffset++] = (byte) (exceptionHandlersNumber >> 8); + this.contents[localContentsOffset++] = (byte) exceptionHandlersNumber; + for (int i = 0; i < exceptionHandlersNumber; i++) { + ExceptionLabel exceptionHandler = exceptionHandlers[i]; + int start = exceptionHandler.start; + this.contents[localContentsOffset++] = (byte) (start >> 8); + this.contents[localContentsOffset++] = (byte) start; + int end = exceptionHandler.end; + this.contents[localContentsOffset++] = (byte) (end >> 8); + this.contents[localContentsOffset++] = (byte) end; + int handlerPC = exceptionHandler.position; + this.contents[localContentsOffset++] = (byte) (handlerPC >> 8); + this.contents[localContentsOffset++] = (byte) handlerPC; + if (exceptionHandler.exceptionType == null) { + // any exception handler + this.contents[localContentsOffset++] = 0; + this.contents[localContentsOffset++] = 0; + } else { + int nameIndex; + if (exceptionHandler.exceptionType == BaseTypes.NullBinding) { + /* represents ClassNotFoundException, see class literal access*/ + nameIndex = constantPool.literalIndexForJavaLangClassNotFoundException(); + } else { + nameIndex = constantPool.literalIndex(exceptionHandler.exceptionType); + } + this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); + this.contents[localContentsOffset++] = (byte) nameIndex; + } + } + // debug attributes + int codeAttributeAttributeOffset = localContentsOffset; + int attributeNumber = 0; + // leave two bytes for the attribute_length + localContentsOffset += 2; + + // first we handle the linenumber attribute + if (codeStream.generateLineNumberAttributes) { + /* Create and add the line number attribute (used for debugging) + * Build the pairs of: + * (bytecodePC lineNumber) + * according to the table of start line indexes and the pcToSourceMap table + * contained into the codestream + */ + int[] pcToSourceMapTable; + if (((pcToSourceMapTable = codeStream.pcToSourceMap) != null) + && (codeStream.pcToSourceMapSize != 0)) { + int lineNumberNameIndex = + constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName); + if (localContentsOffset + 8 >= this.contents.length) { + resizeContents(8); + } + this.contents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8); + this.contents[localContentsOffset++] = (byte) lineNumberNameIndex; + int lineNumberTableOffset = localContentsOffset; + localContentsOffset += 6; + // leave space for attribute_length and line_number_table_length + int numberOfEntries = 0; + int length = codeStream.pcToSourceMapSize; + for (int i = 0; i < length;) { + // write the entry + if (localContentsOffset + 4 >= this.contents.length) { + resizeContents(4); + } + int pc = pcToSourceMapTable[i++]; + this.contents[localContentsOffset++] = (byte) (pc >> 8); + this.contents[localContentsOffset++] = (byte) pc; + int lineNumber = pcToSourceMapTable[i++]; + this.contents[localContentsOffset++] = (byte) (lineNumber >> 8); + this.contents[localContentsOffset++] = (byte) lineNumber; + numberOfEntries++; + } + // now we change the size of the line number attribute + int lineNumberAttr_length = numberOfEntries * 4 + 2; + this.contents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 24); + this.contents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 16); + this.contents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 8); + this.contents[lineNumberTableOffset++] = (byte) lineNumberAttr_length; + this.contents[lineNumberTableOffset++] = (byte) (numberOfEntries >> 8); + this.contents[lineNumberTableOffset++] = (byte) numberOfEntries; + attributeNumber++; + } + } + // then we do the local variable attribute + if (codeStream.generateLocalVariableTableAttributes) { + int localVariableTableOffset = localContentsOffset; + int numberOfEntries = 0; + int localVariableNameIndex = + constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName); + if (localContentsOffset + 8 >= this.contents.length) { + resizeContents(8); + } + this.contents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8); + this.contents[localContentsOffset++] = (byte) localVariableNameIndex; + localContentsOffset += 6; + // leave space for attribute_length and local_variable_table_length + int nameIndex; + int descriptorIndex; + if (!codeStream.methodDeclaration.isStatic()) { + numberOfEntries++; + if (localContentsOffset + 10 >= this.contents.length) { + resizeContents(10); + } + this.contents[localContentsOffset++] = 0; // the startPC for this is always 0 + this.contents[localContentsOffset++] = 0; + this.contents[localContentsOffset++] = (byte) (code_length >> 8); + this.contents[localContentsOffset++] = (byte) code_length; + nameIndex = constantPool.literalIndex(QualifiedNamesConstants.This); + this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); + this.contents[localContentsOffset++] = (byte) nameIndex; + descriptorIndex = + constantPool.literalIndex( + codeStream.methodDeclaration.binding.declaringClass.signature()); + this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8); + this.contents[localContentsOffset++] = (byte) descriptorIndex; + this.contents[localContentsOffset++] = 0;// the resolved position for this is always 0 + this.contents[localContentsOffset++] = 0; + } + for (int i = 0; i < codeStream.allLocalsCounter; i++) { + LocalVariableBinding localVariable = codeStream.locals[i]; + for (int j = 0; j < localVariable.initializationCount; j++) { + int startPC = localVariable.initializationPCs[j << 1]; + int endPC = localVariable.initializationPCs[(j << 1) + 1]; + if (startPC != endPC) { // only entries for non zero length + if (endPC == -1) { + localVariable.declaringScope.problemReporter().abortDueToInternalError( + Util.bind("abort.invalidAttribute" , new String(localVariable.name)), //$NON-NLS-1$ + (ASTNode) localVariable.declaringScope.methodScope().referenceContext); + } + if (localContentsOffset + 10 >= this.contents.length) { + resizeContents(10); + } + // now we can safely add the local entry + numberOfEntries++; + this.contents[localContentsOffset++] = (byte) (startPC >> 8); + this.contents[localContentsOffset++] = (byte) startPC; + int length = endPC - startPC; + this.contents[localContentsOffset++] = (byte) (length >> 8); + this.contents[localContentsOffset++] = (byte) length; + nameIndex = constantPool.literalIndex(localVariable.name); + this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); + this.contents[localContentsOffset++] = (byte) nameIndex; + descriptorIndex = constantPool.literalIndex(localVariable.type.signature()); + this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8); + this.contents[localContentsOffset++] = (byte) descriptorIndex; + int resolvedPosition = localVariable.resolvedPosition; + this.contents[localContentsOffset++] = (byte) (resolvedPosition >> 8); + this.contents[localContentsOffset++] = (byte) resolvedPosition; + } + } + } + int value = numberOfEntries * 10 + 2; + localVariableTableOffset += 2; + this.contents[localVariableTableOffset++] = (byte) (value >> 24); + this.contents[localVariableTableOffset++] = (byte) (value >> 16); + this.contents[localVariableTableOffset++] = (byte) (value >> 8); + this.contents[localVariableTableOffset++] = (byte) value; + this.contents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8); + this.contents[localVariableTableOffset] = (byte) numberOfEntries; + attributeNumber++; + } + // update the number of attributes + // ensure first that there is enough space available inside the localContents array + if (codeAttributeAttributeOffset + 2 >= this.contents.length) { + resizeContents(2); + } + this.contents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8); + this.contents[codeAttributeAttributeOffset] = (byte) attributeNumber; + + // update the attribute length + int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6); + this.contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24); + this.contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16); + this.contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8); + this.contents[codeAttributeOffset + 5] = (byte) codeAttributeLength; + contentsOffset = localContentsOffset; + } + + /** + * INTERNAL USE-ONLY + * That method completes the creation of the code attribute by setting + * - the attribute_length + * - max_stack + * - max_locals + * - code_length + * - exception table + * - and debug attributes if necessary. + * + * @param codeAttributeOffset int + */ + public void completeCodeAttributeForClinit(int codeAttributeOffset) { + // reinitialize the contents with the byte modified by the code stream + this.contents = codeStream.bCodeStream; + int localContentsOffset = codeStream.classFileOffset; + // codeAttributeOffset is the position inside contents byte array before we started to write + // any information about the codeAttribute + // That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset + // to get the right position, 6 for the max_stack etc... + int code_length = codeStream.position; + if (code_length > 65535) { + codeStream.methodDeclaration.scope.problemReporter().bytecodeExceeds64KLimit( + codeStream.methodDeclaration.scope.referenceType()); + } + if (localContentsOffset + 20 >= this.contents.length) { + resizeContents(20); + } + int max_stack = codeStream.stackMax; + this.contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8); + this.contents[codeAttributeOffset + 7] = (byte) max_stack; + int max_locals = codeStream.maxLocals; + this.contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8); + this.contents[codeAttributeOffset + 9] = (byte) max_locals; + this.contents[codeAttributeOffset + 10] = (byte) (code_length >> 24); + this.contents[codeAttributeOffset + 11] = (byte) (code_length >> 16); + this.contents[codeAttributeOffset + 12] = (byte) (code_length >> 8); + this.contents[codeAttributeOffset + 13] = (byte) code_length; + + // write the exception table + int exceptionHandlersNumber = codeStream.exceptionHandlersNumber; + ExceptionLabel[] exceptionHandlers = codeStream.exceptionHandlers; + int exSize = exceptionHandlersNumber * 8 + 2; + if (exSize + localContentsOffset >= this.contents.length) { + resizeContents(exSize); + } + // there is no exception table, so we need to offset by 2 the current offset and move + // on the attribute generation + this.contents[localContentsOffset++] = (byte) (exceptionHandlersNumber >> 8); + this.contents[localContentsOffset++] = (byte) exceptionHandlersNumber; + for (int i = 0; i < exceptionHandlersNumber; i++) { + ExceptionLabel exceptionHandler = exceptionHandlers[i]; + int start = exceptionHandler.start; + this.contents[localContentsOffset++] = (byte) (start >> 8); + this.contents[localContentsOffset++] = (byte) start; + int end = exceptionHandler.end; + this.contents[localContentsOffset++] = (byte) (end >> 8); + this.contents[localContentsOffset++] = (byte) end; + int handlerPC = exceptionHandler.position; + this.contents[localContentsOffset++] = (byte) (handlerPC >> 8); + this.contents[localContentsOffset++] = (byte) handlerPC; + if (exceptionHandler.exceptionType == null) { + // any exception handler + this.contents[localContentsOffset++] = 0; + this.contents[localContentsOffset++] = 0; + } else { + int nameIndex; + if (exceptionHandler.exceptionType == BaseTypes.NullBinding) { + /* represents denote ClassNotFoundException, see class literal access*/ + nameIndex = constantPool.literalIndexForJavaLangClassNotFoundException(); + } else { + nameIndex = constantPool.literalIndex(exceptionHandler.exceptionType); + } + this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); + this.contents[localContentsOffset++] = (byte) nameIndex; + } + } + // debug attributes + int codeAttributeAttributeOffset = localContentsOffset; + int attributeNumber = 0; + // leave two bytes for the attribute_length + localContentsOffset += 2; + + // first we handle the linenumber attribute + if (codeStream.generateLineNumberAttributes) { + /* Create and add the line number attribute (used for debugging) + * Build the pairs of: + * (bytecodePC lineNumber) + * according to the table of start line indexes and the pcToSourceMap table + * contained into the codestream + */ + int[] pcToSourceMapTable; + if (((pcToSourceMapTable = codeStream.pcToSourceMap) != null) + && (codeStream.pcToSourceMapSize != 0)) { + int lineNumberNameIndex = + constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName); + if (localContentsOffset + 8 >= this.contents.length) { + resizeContents(8); + } + this.contents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8); + this.contents[localContentsOffset++] = (byte) lineNumberNameIndex; + int lineNumberTableOffset = localContentsOffset; + localContentsOffset += 6; + // leave space for attribute_length and line_number_table_length + int numberOfEntries = 0; + int length = codeStream.pcToSourceMapSize; + for (int i = 0; i < length;) { + // write the entry + if (localContentsOffset + 4 >= this.contents.length) { + resizeContents(4); + } + int pc = pcToSourceMapTable[i++]; + this.contents[localContentsOffset++] = (byte) (pc >> 8); + this.contents[localContentsOffset++] = (byte) pc; + int lineNumber = pcToSourceMapTable[i++]; + this.contents[localContentsOffset++] = (byte) (lineNumber >> 8); + this.contents[localContentsOffset++] = (byte) lineNumber; + numberOfEntries++; + } + // now we change the size of the line number attribute + int lineNumberAttr_length = numberOfEntries * 4 + 2; + this.contents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 24); + this.contents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 16); + this.contents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 8); + this.contents[lineNumberTableOffset++] = (byte) lineNumberAttr_length; + this.contents[lineNumberTableOffset++] = (byte) (numberOfEntries >> 8); + this.contents[lineNumberTableOffset++] = (byte) numberOfEntries; + attributeNumber++; + } + } + // then we do the local variable attribute + if (codeStream.generateLocalVariableTableAttributes) { + int localVariableTableOffset = localContentsOffset; + int numberOfEntries = 0; + // codeAttribute.addLocalVariableTableAttribute(this); + if ((codeStream.pcToSourceMap != null) + && (codeStream.pcToSourceMapSize != 0)) { + int localVariableNameIndex = + constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName); + if (localContentsOffset + 8 >= this.contents.length) { + resizeContents(8); + } + this.contents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8); + this.contents[localContentsOffset++] = (byte) localVariableNameIndex; + localContentsOffset += 6; + // leave space for attribute_length and local_variable_table_length + int nameIndex; + int descriptorIndex; + for (int i = 0; i < codeStream.allLocalsCounter; i++) { + LocalVariableBinding localVariable = codeStream.locals[i]; + for (int j = 0; j < localVariable.initializationCount; j++) { + int startPC = localVariable.initializationPCs[j << 1]; + int endPC = localVariable.initializationPCs[(j << 1) + 1]; + if (startPC != endPC) { // only entries for non zero length + if (endPC == -1) { + localVariable.declaringScope.problemReporter().abortDueToInternalError( + Util.bind("abort.invalidAttribute" , new String(localVariable.name)), //$NON-NLS-1$ + (ASTNode) localVariable.declaringScope.methodScope().referenceContext); + } + if (localContentsOffset + 10 >= this.contents.length) { + resizeContents(10); + } + // now we can safely add the local entry + numberOfEntries++; + this.contents[localContentsOffset++] = (byte) (startPC >> 8); + this.contents[localContentsOffset++] = (byte) startPC; + int length = endPC - startPC; + this.contents[localContentsOffset++] = (byte) (length >> 8); + this.contents[localContentsOffset++] = (byte) length; + nameIndex = constantPool.literalIndex(localVariable.name); + this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); + this.contents[localContentsOffset++] = (byte) nameIndex; + descriptorIndex = constantPool.literalIndex(localVariable.type.signature()); + this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8); + this.contents[localContentsOffset++] = (byte) descriptorIndex; + int resolvedPosition = localVariable.resolvedPosition; + this.contents[localContentsOffset++] = (byte) (resolvedPosition >> 8); + this.contents[localContentsOffset++] = (byte) resolvedPosition; + } + } + } + int value = numberOfEntries * 10 + 2; + localVariableTableOffset += 2; + this.contents[localVariableTableOffset++] = (byte) (value >> 24); + this.contents[localVariableTableOffset++] = (byte) (value >> 16); + this.contents[localVariableTableOffset++] = (byte) (value >> 8); + this.contents[localVariableTableOffset++] = (byte) value; + this.contents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8); + this.contents[localVariableTableOffset] = (byte) numberOfEntries; + attributeNumber++; + } + } + // update the number of attributes + // ensure first that there is enough space available inside the contents array + if (codeAttributeAttributeOffset + 2 >= this.contents.length) { + resizeContents(2); + } + this.contents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8); + this.contents[codeAttributeAttributeOffset] = (byte) attributeNumber; + // update the attribute length + int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6); + this.contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24); + this.contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16); + this.contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8); + this.contents[codeAttributeOffset + 5] = (byte) codeAttributeLength; + contentsOffset = localContentsOffset; + } + + /** + * INTERNAL USE-ONLY + * That method completes the creation of the code attribute by setting + * - the attribute_length + * - max_stack + * - max_locals + * - code_length + * - exception table + * - and debug attributes if necessary. + * + * @param codeAttributeOffset int + * @param startLineIndexes int[] + */ + public void completeCodeAttributeForClinit( + int codeAttributeOffset, + int[] startLineIndexes) { + // reinitialize the contents with the byte modified by the code stream + this.contents = codeStream.bCodeStream; + int localContentsOffset = codeStream.classFileOffset; + // codeAttributeOffset is the position inside contents byte array before we started to write + // any information about the codeAttribute + // That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset + // to get the right position, 6 for the max_stack etc... + int code_length = codeStream.position; + if (code_length > 65535) { + codeStream.methodDeclaration.scope.problemReporter().bytecodeExceeds64KLimit( + codeStream.methodDeclaration.scope.referenceType()); + } + if (localContentsOffset + 20 >= this.contents.length) { + resizeContents(20); + } + int max_stack = codeStream.stackMax; + this.contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8); + this.contents[codeAttributeOffset + 7] = (byte) max_stack; + int max_locals = codeStream.maxLocals; + this.contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8); + this.contents[codeAttributeOffset + 9] = (byte) max_locals; + this.contents[codeAttributeOffset + 10] = (byte) (code_length >> 24); + this.contents[codeAttributeOffset + 11] = (byte) (code_length >> 16); + this.contents[codeAttributeOffset + 12] = (byte) (code_length >> 8); + this.contents[codeAttributeOffset + 13] = (byte) code_length; + + // write the exception table + this.contents[localContentsOffset++] = 0; + this.contents[localContentsOffset++] = 0; + + // debug attributes + int codeAttributeAttributeOffset = localContentsOffset; + int attributeNumber = 0; // leave two bytes for the attribute_length + localContentsOffset += 2; // first we handle the linenumber attribute + + // first we handle the linenumber attribute + if (codeStream.generateLineNumberAttributes) { + if (localContentsOffset + 20 >= this.contents.length) { + resizeContents(20); + } + /* Create and add the line number attribute (used for debugging) + * Build the pairs of: + * (bytecodePC lineNumber) + * according to the table of start line indexes and the pcToSourceMap table + * contained into the codestream + */ + int lineNumberNameIndex = + constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName); + this.contents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8); + this.contents[localContentsOffset++] = (byte) lineNumberNameIndex; + this.contents[localContentsOffset++] = 0; + this.contents[localContentsOffset++] = 0; + this.contents[localContentsOffset++] = 0; + this.contents[localContentsOffset++] = 6; + this.contents[localContentsOffset++] = 0; + this.contents[localContentsOffset++] = 1; + // first entry at pc = 0 + this.contents[localContentsOffset++] = 0; + this.contents[localContentsOffset++] = 0; + this.contents[localContentsOffset++] = (byte) (problemLine >> 8); + this.contents[localContentsOffset++] = (byte) problemLine; + // now we change the size of the line number attribute + attributeNumber++; + } + // then we do the local variable attribute + if (codeStream.generateLocalVariableTableAttributes) { + int localVariableNameIndex = + constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName); + if (localContentsOffset + 8 >= this.contents.length) { + resizeContents(8); + } + this.contents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8); + this.contents[localContentsOffset++] = (byte) localVariableNameIndex; + this.contents[localContentsOffset++] = 0; + this.contents[localContentsOffset++] = 0; + this.contents[localContentsOffset++] = 0; + this.contents[localContentsOffset++] = 2; + this.contents[localContentsOffset++] = 0; + this.contents[localContentsOffset++] = 0; + attributeNumber++; + } + // update the number of attributes + // ensure first that there is enough space available inside the contents array + if (codeAttributeAttributeOffset + 2 >= this.contents.length) { + resizeContents(2); + } + this.contents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8); + this.contents[codeAttributeAttributeOffset] = (byte) attributeNumber; + // update the attribute length + int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6); + this.contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24); + this.contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16); + this.contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8); + this.contents[codeAttributeOffset + 5] = (byte) codeAttributeLength; + contentsOffset = localContentsOffset; + } + + /** + * INTERNAL USE-ONLY + * That method completes the creation of the code attribute by setting + * - the attribute_length + * - max_stack + * - max_locals + * - code_length + * - exception table + * - and debug attributes if necessary. + * + * @param codeAttributeOffset int + */ + public void completeCodeAttributeForProblemMethod( + AbstractMethodDeclaration method, + MethodBinding binding, + int codeAttributeOffset, + int[] startLineIndexes) { + // reinitialize the localContents with the byte modified by the code stream + this.contents = codeStream.bCodeStream; + int localContentsOffset = codeStream.classFileOffset; + // codeAttributeOffset is the position inside localContents byte array before we started to write// any information about the codeAttribute// That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset// to get the right position, 6 for the max_stack etc... + int max_stack = codeStream.stackMax; + this.contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8); + this.contents[codeAttributeOffset + 7] = (byte) max_stack; + int max_locals = codeStream.maxLocals; + this.contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8); + this.contents[codeAttributeOffset + 9] = (byte) max_locals; + int code_length = codeStream.position; + this.contents[codeAttributeOffset + 10] = (byte) (code_length >> 24); + this.contents[codeAttributeOffset + 11] = (byte) (code_length >> 16); + this.contents[codeAttributeOffset + 12] = (byte) (code_length >> 8); + this.contents[codeAttributeOffset + 13] = (byte) code_length; + // write the exception table + if (localContentsOffset + 50 >= this.contents.length) { + resizeContents(50); + } + + // write the exception table + this.contents[localContentsOffset++] = 0; + this.contents[localContentsOffset++] = 0; + // debug attributes + int codeAttributeAttributeOffset = localContentsOffset; + int attributeNumber = 0; // leave two bytes for the attribute_length + localContentsOffset += 2; // first we handle the linenumber attribute + + if (codeStream.generateLineNumberAttributes) { + if (localContentsOffset + 20 >= this.contents.length) { + resizeContents(20); + } + /* Create and add the line number attribute (used for debugging) + * Build the pairs of: + * (bytecodePC lineNumber) + * according to the table of start line indexes and the pcToSourceMap table + * contained into the codestream + */ + int lineNumberNameIndex = + constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName); + this.contents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8); + this.contents[localContentsOffset++] = (byte) lineNumberNameIndex; + this.contents[localContentsOffset++] = 0; + this.contents[localContentsOffset++] = 0; + this.contents[localContentsOffset++] = 0; + this.contents[localContentsOffset++] = 6; + this.contents[localContentsOffset++] = 0; + this.contents[localContentsOffset++] = 1; + if (problemLine == 0) { + problemLine = searchLineNumber(startLineIndexes, binding.sourceStart()); + } + // first entry at pc = 0 + this.contents[localContentsOffset++] = 0; + this.contents[localContentsOffset++] = 0; + this.contents[localContentsOffset++] = (byte) (problemLine >> 8); + this.contents[localContentsOffset++] = (byte) problemLine; + // now we change the size of the line number attribute + attributeNumber++; + } + // then we do the local variable attribute + if (codeStream.generateLocalVariableTableAttributes) { + // compute the resolved position for the arguments of the method + int argSize; + int localVariableTableOffset = localContentsOffset; + int numberOfEntries = 0; + // codeAttribute.addLocalVariableTableAttribute(this); + int localVariableNameIndex = + constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName); + if (localContentsOffset + 8 >= this.contents.length) { + resizeContents(8); + } + this.contents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8); + this.contents[localContentsOffset++] = (byte) localVariableNameIndex; + localContentsOffset += 6; + // leave space for attribute_length and local_variable_table_length + int descriptorIndex; + if (!codeStream.methodDeclaration.isStatic()) { + numberOfEntries++; + if (localContentsOffset + 10 >= this.contents.length) { + resizeContents(10); + } + this.contents[localContentsOffset++] = 0; + this.contents[localContentsOffset++] = 0; + this.contents[localContentsOffset++] = (byte) (code_length >> 8); + this.contents[localContentsOffset++] = (byte) code_length; + int nameIndex = constantPool.literalIndex(QualifiedNamesConstants.This); + this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); + this.contents[localContentsOffset++] = (byte) nameIndex; + descriptorIndex = + constantPool.literalIndex( + codeStream.methodDeclaration.binding.declaringClass.signature()); + this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8); + this.contents[localContentsOffset++] = (byte) descriptorIndex; + // the resolved position for this is always 0 + this.contents[localContentsOffset++] = 0; + this.contents[localContentsOffset++] = 0; + } + if (binding.isConstructor()) { + ReferenceBinding declaringClass = binding.declaringClass; + if (declaringClass.isNestedType()) { + NestedTypeBinding methodDeclaringClass = (NestedTypeBinding) declaringClass; + argSize = methodDeclaringClass.enclosingInstancesSlotSize; + SyntheticArgumentBinding[] syntheticArguments; + if ((syntheticArguments = methodDeclaringClass.syntheticEnclosingInstances()) + != null) { + for (int i = 0, max = syntheticArguments.length; i < max; i++) { + LocalVariableBinding localVariable = syntheticArguments[i]; + if (localContentsOffset + 10 >= this.contents.length) { + resizeContents(10); + } + // now we can safely add the local entry + numberOfEntries++; + this.contents[localContentsOffset++] = 0; + this.contents[localContentsOffset++] = 0; + this.contents[localContentsOffset++] = (byte) (code_length >> 8); + this.contents[localContentsOffset++] = (byte) code_length; + int nameIndex = constantPool.literalIndex(localVariable.name); + this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); + this.contents[localContentsOffset++] = (byte) nameIndex; + descriptorIndex = constantPool.literalIndex(localVariable.type.signature()); + this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8); + this.contents[localContentsOffset++] = (byte) descriptorIndex; + int resolvedPosition = localVariable.resolvedPosition; + this.contents[localContentsOffset++] = (byte) (resolvedPosition >> 8); + this.contents[localContentsOffset++] = (byte) resolvedPosition; + } + } + } else { + argSize = 1; + } + } else { + argSize = binding.isStatic() ? 0 : 1; + } + if (method.binding != null) { + TypeBinding[] parameters = method.binding.parameters; + Argument[] arguments = method.arguments; + if ((parameters != null) && (arguments != null)) { + for (int i = 0, max = parameters.length; i < max; i++) { + TypeBinding argumentBinding = parameters[i]; + if (localContentsOffset + 10 >= this.contents.length) { + resizeContents(10); + } + // now we can safely add the local entry + numberOfEntries++; + this.contents[localContentsOffset++] = 0; + this.contents[localContentsOffset++] = 0; + this.contents[localContentsOffset++] = (byte) (code_length >> 8); + this.contents[localContentsOffset++] = (byte) code_length; + int nameIndex = constantPool.literalIndex(arguments[i].name); + this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); + this.contents[localContentsOffset++] = (byte) nameIndex; + descriptorIndex = constantPool.literalIndex(argumentBinding.signature()); + this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8); + this.contents[localContentsOffset++] = (byte) descriptorIndex; + int resolvedPosition = argSize; + if ((argumentBinding == BaseTypes.LongBinding) + || (argumentBinding == BaseTypes.DoubleBinding)) + argSize += 2; + else + argSize++; + this.contents[localContentsOffset++] = (byte) (resolvedPosition >> 8); + this.contents[localContentsOffset++] = (byte) resolvedPosition; + } + } + } + int value = numberOfEntries * 10 + 2; + localVariableTableOffset += 2; + this.contents[localVariableTableOffset++] = (byte) (value >> 24); + this.contents[localVariableTableOffset++] = (byte) (value >> 16); + this.contents[localVariableTableOffset++] = (byte) (value >> 8); + this.contents[localVariableTableOffset++] = (byte) value; + this.contents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8); + this.contents[localVariableTableOffset] = (byte) numberOfEntries; + attributeNumber++; + } + // update the number of attributes// ensure first that there is enough space available inside the localContents array + if (codeAttributeAttributeOffset + 2 >= this.contents.length) { + resizeContents(2); + } + this.contents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8); + this.contents[codeAttributeAttributeOffset] = (byte) attributeNumber; + // update the attribute length + int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6); + this.contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24); + this.contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16); + this.contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8); + this.contents[codeAttributeOffset + 5] = (byte) codeAttributeLength; + contentsOffset = localContentsOffset; + } + + /** + * INTERNAL USE-ONLY + * That method completes the creation of the code attribute by setting + * - the attribute_length + * - max_stack + * - max_locals + * - code_length + * - exception table + * - and debug attributes if necessary. + * + * @param binding org.eclipse.jdt.internal.compiler.lookup.SyntheticAccessMethodBinding + * @param codeAttributeOffset int + */ + public void completeCodeAttributeForSyntheticAccessMethod( + SyntheticAccessMethodBinding binding, + int codeAttributeOffset, + int[] startLineIndexes) { + // reinitialize the contents with the byte modified by the code stream + this.contents = codeStream.bCodeStream; + int localContentsOffset = codeStream.classFileOffset; + // codeAttributeOffset is the position inside contents byte array before we started to write + // any information about the codeAttribute + // That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset + // to get the right position, 6 for the max_stack etc... + int max_stack = codeStream.stackMax; + contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8); + contents[codeAttributeOffset + 7] = (byte) max_stack; + int max_locals = codeStream.maxLocals; + contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8); + contents[codeAttributeOffset + 9] = (byte) max_locals; + int code_length = codeStream.position; + contents[codeAttributeOffset + 10] = (byte) (code_length >> 24); + contents[codeAttributeOffset + 11] = (byte) (code_length >> 16); + contents[codeAttributeOffset + 12] = (byte) (code_length >> 8); + contents[codeAttributeOffset + 13] = (byte) code_length; + if ((localContentsOffset + 40) >= this.contents.length) { + resizeContents(40); + } + // there is no exception table, so we need to offset by 2 the current offset and move + // on the attribute generation + contents[localContentsOffset++] = 0; + contents[localContentsOffset++] = 0; + // debug attributes + int codeAttributeAttributeOffset = localContentsOffset; + int attributeNumber = 0; + // leave two bytes for the attribute_length + localContentsOffset += 2; + + // first we handle the linenumber attribute + if (codeStream.generateLineNumberAttributes) { + int index = 0; + int lineNumberNameIndex = + constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName); + contents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8); + contents[localContentsOffset++] = (byte) lineNumberNameIndex; + int lineNumberTableOffset = localContentsOffset; + localContentsOffset += 6; + // leave space for attribute_length and line_number_table_length + // Seems like do would be better, but this preserves the existing behavior. + index = searchLineNumber(startLineIndexes, binding.sourceStart); + contents[localContentsOffset++] = 0; + contents[localContentsOffset++] = 0; + contents[localContentsOffset++] = (byte) (index >> 8); + contents[localContentsOffset++] = (byte) index; + // now we change the size of the line number attribute + contents[lineNumberTableOffset++] = 0; + contents[lineNumberTableOffset++] = 0; + contents[lineNumberTableOffset++] = 0; + contents[lineNumberTableOffset++] = 6; + contents[lineNumberTableOffset++] = 0; + contents[lineNumberTableOffset++] = 1; + attributeNumber++; + } + // then we do the local variable attribute + if (codeStream.generateLocalVariableTableAttributes) { + int localVariableTableOffset = localContentsOffset; + int numberOfEntries = 0; + int localVariableNameIndex = + constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName); + if (localContentsOffset + 8 > this.contents.length) { + resizeContents(8); + } + contents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8); + contents[localContentsOffset++] = (byte) localVariableNameIndex; + localContentsOffset += 6; + // leave space for attribute_length and local_variable_table_length + int nameIndex; + int descriptorIndex; + for (int i = 0; i < codeStream.allLocalsCounter; i++) { + LocalVariableBinding localVariable = codeStream.locals[i]; + for (int j = 0; j < localVariable.initializationCount; j++) { + int startPC = localVariable.initializationPCs[j << 1]; + int endPC = localVariable.initializationPCs[(j << 1) + 1]; + if (startPC != endPC) { // only entries for non zero length + if (endPC == -1) { + localVariable.declaringScope.problemReporter().abortDueToInternalError( + Util.bind("abort.invalidAttribute" , new String(localVariable.name)), //$NON-NLS-1$ + (ASTNode) localVariable.declaringScope.methodScope().referenceContext); + } + if (localContentsOffset + 10 > this.contents.length) { + resizeContents(10); + } + // now we can safely add the local entry + numberOfEntries++; + contents[localContentsOffset++] = (byte) (startPC >> 8); + contents[localContentsOffset++] = (byte) startPC; + int length = endPC - startPC; + contents[localContentsOffset++] = (byte) (length >> 8); + contents[localContentsOffset++] = (byte) length; + nameIndex = constantPool.literalIndex(localVariable.name); + contents[localContentsOffset++] = (byte) (nameIndex >> 8); + contents[localContentsOffset++] = (byte) nameIndex; + descriptorIndex = constantPool.literalIndex(localVariable.type.signature()); + contents[localContentsOffset++] = (byte) (descriptorIndex >> 8); + contents[localContentsOffset++] = (byte) descriptorIndex; + int resolvedPosition = localVariable.resolvedPosition; + contents[localContentsOffset++] = (byte) (resolvedPosition >> 8); + contents[localContentsOffset++] = (byte) resolvedPosition; + } + } + } + int value = numberOfEntries * 10 + 2; + localVariableTableOffset += 2; + contents[localVariableTableOffset++] = (byte) (value >> 24); + contents[localVariableTableOffset++] = (byte) (value >> 16); + contents[localVariableTableOffset++] = (byte) (value >> 8); + contents[localVariableTableOffset++] = (byte) value; + contents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8); + contents[localVariableTableOffset] = (byte) numberOfEntries; + attributeNumber++; + } + // update the number of attributes + // ensure first that there is enough space available inside the contents array + if (codeAttributeAttributeOffset + 2 >= this.contents.length) { + resizeContents(2); + } + contents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8); + contents[codeAttributeAttributeOffset] = (byte) attributeNumber; + + // update the attribute length + int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6); + contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24); + contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16); + contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8); + contents[codeAttributeOffset + 5] = (byte) codeAttributeLength; + contentsOffset = localContentsOffset; + } + + /** + * INTERNAL USE-ONLY + * Complete the creation of a method info by setting up the number of attributes at the right offset. + * + * @param methodAttributeOffset int + * @param attributeNumber int + */ + public void completeMethodInfo( + int methodAttributeOffset, + int attributeNumber) { + // update the number of attributes + contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8); + contents[methodAttributeOffset] = (byte) attributeNumber; + } + + /** + * INTERNAL USE-ONLY + * Request the creation of a ClassFile compatible representation of a problematic type + * + * @param typeDeclaration org.eclipse.jdt.internal.compiler.ast.TypeDeclaration + * @param unitResult org.eclipse.jdt.internal.compiler.CompilationUnitResult + */ + public static void createProblemType( + TypeDeclaration typeDeclaration, + CompilationResult unitResult) { + SourceTypeBinding typeBinding = typeDeclaration.binding; + ClassFile classFile = new ClassFile(typeBinding, null, true); + + // TODO (olivier) handle cases where a field cannot be generated (name too long) + // TODO (olivier) handle too many methods + // inner attributes + if (typeBinding.isMemberType()) + classFile.recordEnclosingTypeAttributes(typeBinding); + + // add its fields + FieldBinding[] fields = typeBinding.fields; + if ((fields != null) && (fields != NoFields)) { + for (int i = 0, max = fields.length; i < max; i++) { + if (fields[i].constant == null) { + FieldReference.getConstantFor(fields[i], null, false, null); + } + } + classFile.addFieldInfos(); + } else { + // we have to set the number of fields to be equals to 0 + classFile.contents[classFile.contentsOffset++] = 0; + classFile.contents[classFile.contentsOffset++] = 0; + } + // leave some space for the methodCount + classFile.setForMethodInfos(); + // add its user defined methods + MethodBinding[] methods = typeBinding.methods; + AbstractMethodDeclaration[] methodDeclarations = typeDeclaration.methods; + int maxMethodDecl = methodDeclarations == null ? 0 : methodDeclarations.length; + int problemsLength; + IProblem[] problems = unitResult.getErrors(); + if (problems == null) { + problems = new IProblem[0]; + } + IProblem[] problemsCopy = new IProblem[problemsLength = problems.length]; + System.arraycopy(problems, 0, problemsCopy, 0, problemsLength); + if (methods != null) { + if (typeBinding.isInterface()) { + // we cannot create problem methods for an interface. So we have to generate a clinit + // which should contain all the problem + classFile.addProblemClinit(problemsCopy); + for (int i = 0, max = methods.length; i < max; i++) { + MethodBinding methodBinding; + if ((methodBinding = methods[i]) != null) { + // find the corresponding method declaration + for (int j = 0; j < maxMethodDecl; j++) { + if ((methodDeclarations[j] != null) + && (methodDeclarations[j].binding == methods[i])) { + if (!methodBinding.isConstructor()) { + classFile.addAbstractMethod(methodDeclarations[j], methodBinding); + } + break; + } + } + } + } + } else { + for (int i = 0, max = methods.length; i < max; i++) { + MethodBinding methodBinding; + if ((methodBinding = methods[i]) != null) { + // find the corresponding method declaration + for (int j = 0; j < maxMethodDecl; j++) { + if ((methodDeclarations[j] != null) + && (methodDeclarations[j].binding == methods[i])) { + AbstractMethodDeclaration methodDecl; + if ((methodDecl = methodDeclarations[j]).isConstructor()) { + classFile.addProblemConstructor(methodDecl, methodBinding, problemsCopy); + } else { + classFile.addProblemMethod(methodDecl, methodBinding, problemsCopy); + } + break; + } + } + } + } + } + // add abstract methods + classFile.addDefaultAbstractMethods(); + } + // propagate generation of (problem) member types + if (typeDeclaration.memberTypes != null) { + for (int i = 0, max = typeDeclaration.memberTypes.length; i < max; i++) { + TypeDeclaration memberType = typeDeclaration.memberTypes[i]; + if (memberType.binding != null) { + classFile.recordNestedMemberAttribute(memberType.binding); + ClassFile.createProblemType(memberType, unitResult); + } + } + } + classFile.addAttributes(); + unitResult.record(typeBinding.constantPoolName(), classFile); + } + + /** + * INTERNAL USE-ONLY + * This methods returns a char[] representing the file name of the receiver + * + * @return char[] + */ + public char[] fileName() { + return constantPool.UTF8Cache.returnKeyFor(1); + } + + /** + * INTERNAL USE-ONLY + * That method generates the header of a code attribute. + * - the index inside the constant pool for the attribute name ("Code") + * - leave some space for attribute_length(4), max_stack(2), max_locals(2), code_length(4). + */ + public void generateCodeAttributeHeader() { + if (contentsOffset + 20 >= this.contents.length) { + resizeContents(20); + } + int constantValueNameIndex = + constantPool.literalIndex(AttributeNamesConstants.CodeName); + contents[contentsOffset++] = (byte) (constantValueNameIndex >> 8); + contents[contentsOffset++] = (byte) constantValueNameIndex; + // leave space for attribute_length(4), max_stack(2), max_locals(2), code_length(4) + contentsOffset += 12; + } + + /** + * INTERNAL USE-ONLY + * That method generates the attributes of a code attribute. + * They could be: + * - an exception attribute for each try/catch found inside the method + * - a deprecated attribute + * - a synthetic attribute for synthetic access methods + * + * It returns the number of attributes created for the code attribute. + * + * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding + * @return int + */ + public int generateMethodInfoAttribute(MethodBinding methodBinding) { + // leave two bytes for the attribute_number + contentsOffset += 2; + // now we can handle all the attribute for that method info: + // it could be: + // - a CodeAttribute + // - a ExceptionAttribute + // - a DeprecatedAttribute + // - a SyntheticAttribute + + // Exception attribute + ReferenceBinding[] thrownsExceptions; + int attributeNumber = 0; + if ((thrownsExceptions = methodBinding.thrownExceptions) != NoExceptions) { + // The method has a throw clause. So we need to add an exception attribute + // check that there is enough space to write all the bytes for the exception attribute + int length = thrownsExceptions.length; + int exSize = 8 + length * 2; + if (exSize + contentsOffset >= this.contents.length) { + resizeContents(exSize); + } + int exceptionNameIndex = + constantPool.literalIndex(AttributeNamesConstants.ExceptionsName); + contents[contentsOffset++] = (byte) (exceptionNameIndex >> 8); + contents[contentsOffset++] = (byte) exceptionNameIndex; + // The attribute length = length * 2 + 2 in case of a exception attribute + int attributeLength = length * 2 + 2; + contents[contentsOffset++] = (byte) (attributeLength >> 24); + contents[contentsOffset++] = (byte) (attributeLength >> 16); + contents[contentsOffset++] = (byte) (attributeLength >> 8); + contents[contentsOffset++] = (byte) attributeLength; + contents[contentsOffset++] = (byte) (length >> 8); + contents[contentsOffset++] = (byte) length; + for (int i = 0; i < length; i++) { + int exceptionIndex = constantPool.literalIndex(thrownsExceptions[i]); + contents[contentsOffset++] = (byte) (exceptionIndex >> 8); + contents[contentsOffset++] = (byte) exceptionIndex; + } + attributeNumber++; + } + if (methodBinding.isDeprecated()) { + // Deprecated attribute + // Check that there is enough space to write the deprecated attribute + if (contentsOffset + 6 >= this.contents.length) { + resizeContents(6); + } + int deprecatedAttributeNameIndex = + constantPool.literalIndex(AttributeNamesConstants.DeprecatedName); + contents[contentsOffset++] = (byte) (deprecatedAttributeNameIndex >> 8); + contents[contentsOffset++] = (byte) deprecatedAttributeNameIndex; + // the length of a deprecated attribute is equals to 0 + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + + attributeNumber++; + } + if (this.targetJDK < ClassFileConstants.JDK1_5 && methodBinding.isSynthetic()) { + // Synthetic attribute + // Check that there is enough space to write the deprecated attribute + if (contentsOffset + 6 >= this.contents.length) { + resizeContents(6); + } + int syntheticAttributeNameIndex = + constantPool.literalIndex(AttributeNamesConstants.SyntheticName); + contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8); + contents[contentsOffset++] = (byte) syntheticAttributeNameIndex; + // the length of a synthetic attribute is equals to 0 + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 0; + + attributeNumber++; + } + return attributeNumber; + } + + /** + * INTERNAL USE-ONLY + * That method generates the header of a method info: + * The header consists in: + * - the access flags + * - the name index of the method name inside the constant pool + * - the descriptor index of the signature of the method inside the constant pool. + * + * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding + */ + public void generateMethodInfoHeader(MethodBinding methodBinding) { + generateMethodInfoHeader(methodBinding, methodBinding.modifiers); + } + /** + * INTERNAL USE-ONLY + * That method generates the header of a method info: + * The header consists in: + * - the access flags + * - the name index of the method name inside the constant pool + * - the descriptor index of the signature of the method inside the constant pool. + * + * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding + * @param accessFlags the access flags + */ + public void generateMethodInfoHeader(MethodBinding methodBinding, int accessFlags) { + // check that there is enough space to write all the bytes for the method info corresponding + // to the @methodBinding + methodCount++; // add one more method + if (contentsOffset + 10 >= this.contents.length) { + resizeContents(10); + } + if (targetJDK < ClassFileConstants.JDK1_5) { + // pre 1.5, synthetic was an attribute, not a modifier + accessFlags &= ~AccSynthetic; + } + if (methodBinding.isRequiredToClearPrivateModifier()) { + accessFlags &= ~AccPrivate; + } + contents[contentsOffset++] = (byte) (accessFlags >> 8); + contents[contentsOffset++] = (byte) accessFlags; + int nameIndex = constantPool.literalIndex(methodBinding.selector); + contents[contentsOffset++] = (byte) (nameIndex >> 8); + contents[contentsOffset++] = (byte) nameIndex; + int descriptorIndex = constantPool.literalIndex(methodBinding.signature()); + contents[contentsOffset++] = (byte) (descriptorIndex >> 8); + contents[contentsOffset++] = (byte) descriptorIndex; + } + + /** + * INTERNAL USE-ONLY + * That method generates the method info header of a clinit: + * The header consists in: + * - the access flags (always default access + static) + * - the name index of the method name (always ) inside the constant pool + * - the descriptor index of the signature (always ()V) of the method inside the constant pool. + */ + public void generateMethodInfoHeaderForClinit() { + // check that there is enough space to write all the bytes for the method info corresponding + // to the @methodBinding + methodCount++; // add one more method + if (contentsOffset + 10 >= this.contents.length) { + resizeContents(10); + } + contents[contentsOffset++] = (byte) ((AccDefault | AccStatic) >> 8); + contents[contentsOffset++] = (byte) (AccDefault | AccStatic); + int nameIndex = constantPool.literalIndex(QualifiedNamesConstants.Clinit); + contents[contentsOffset++] = (byte) (nameIndex >> 8); + contents[contentsOffset++] = (byte) nameIndex; + int descriptorIndex = + constantPool.literalIndex(QualifiedNamesConstants.ClinitSignature); + contents[contentsOffset++] = (byte) (descriptorIndex >> 8); + contents[contentsOffset++] = (byte) descriptorIndex; + // We know that we won't get more than 1 attribute: the code attribute + contents[contentsOffset++] = 0; + contents[contentsOffset++] = 1; + } + + /** + * EXTERNAL API + * Answer the actual bytes of the class file + * + * This method encodes the receiver structure into a byte array which is the content of the classfile. + * Returns the byte array that represents the encoded structure of the receiver. + * + * @return byte[] + */ + public byte[] getBytes() { + byte[] fullContents = new byte[headerOffset + contentsOffset]; + System.arraycopy(header, 0, fullContents, 0, headerOffset); + System.arraycopy(contents, 0, fullContents, headerOffset, contentsOffset); + return fullContents; + } + + /** + * EXTERNAL API + * Answer the compound name of the class file. + * @return char[][] + * e.g. {{java}, {util}, {Hashtable}}. + */ + public char[][] getCompoundName() { + return CharOperation.splitOn('/', fileName()); + } + + protected void initByteArrays() { + LookupEnvironment env = this.referenceBinding.scope.environment(); + synchronized (env) { + if (env.sharedArraysUsed) { + this.ownSharedArrays = false; + int members = referenceBinding.methods().length + referenceBinding.fields().length; + this.header = new byte[INITIAL_HEADER_SIZE]; + this.contents = new byte[members < 15 ? INITIAL_CONTENTS_SIZE : INITIAL_HEADER_SIZE]; + } else { + this.ownSharedArrays = env.sharedArraysUsed = true; + this.header = env.sharedClassFileHeader; + this.contents = env.sharedClassFileContents; + } + } + } + + /** + * INTERNAL USE-ONLY + * Returns the most enclosing classfile of the receiver. This is used know to store the constant pool name + * for all inner types of the receiver. + * @return org.eclipse.jdt.internal.compiler.codegen.ClassFile + */ + public ClassFile outerMostEnclosingClassFile() { + ClassFile current = this; + while (current.enclosingClassFile != null) + current = current.enclosingClassFile; + return current; + } + + /** + * INTERNAL USE-ONLY + * This is used to store a new inner class. It checks that the binding @binding doesn't already exist inside the + * collection of inner classes. Add all the necessary classes in the right order to fit to the specifications. + * + * @param binding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding + */ + public void recordEnclosingTypeAttributes(ReferenceBinding binding) { + // add all the enclosing types + ReferenceBinding enclosingType = referenceBinding.enclosingType(); + int depth = 0; + while (enclosingType != null) { + depth++; + enclosingType = enclosingType.enclosingType(); + } + enclosingType = referenceBinding; + ReferenceBinding enclosingTypes[]; + if (depth >= 2) { + enclosingTypes = new ReferenceBinding[depth]; + for (int i = depth - 1; i >= 0; i--) { + enclosingTypes[i] = enclosingType; + enclosingType = enclosingType.enclosingType(); + } + for (int i = 0; i < depth; i++) { + addInnerClasses(enclosingTypes[i]); + } + } else { + addInnerClasses(referenceBinding); + } + } + + /** + * INTERNAL USE-ONLY + * This is used to store a new inner class. It checks that the binding @binding doesn't already exist inside the + * collection of inner classes. Add all the necessary classes in the right order to fit to the specifications. + * + * @param binding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding + */ + public void recordNestedLocalAttribute(ReferenceBinding binding) { + // add all the enclosing types + ReferenceBinding enclosingType = referenceBinding.enclosingType(); + int depth = 0; + while (enclosingType != null) { + depth++; + enclosingType = enclosingType.enclosingType(); + } + enclosingType = referenceBinding; + ReferenceBinding enclosingTypes[]; + if (depth >= 2) { + enclosingTypes = new ReferenceBinding[depth]; + for (int i = depth - 1; i >= 0; i--) { + enclosingTypes[i] = enclosingType; + enclosingType = enclosingType.enclosingType(); + } + for (int i = 0; i < depth; i++) + addInnerClasses(enclosingTypes[i]); + } else { + addInnerClasses(binding); + } + } + + /** + * INTERNAL USE-ONLY + * This is used to store a new inner class. It checks that the binding @binding doesn't already exist inside the + * collection of inner classes. Add all the necessary classes in the right order to fit to the specifications. + * + * @param binding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding + */ + public void recordNestedMemberAttribute(ReferenceBinding binding) { + addInnerClasses(binding); + } + + /** + * Resize the pool contents + */ + private final void resizeContents(int minimalSize) { + int length = this.contents.length; + int toAdd = length; + if (toAdd < minimalSize) + toAdd = minimalSize; + System.arraycopy(this.contents, 0, this.contents = new byte[length + toAdd], 0, length); + } + + /** + * INTERNAL USE-ONLY + * Search the line number corresponding to a specific position + */ + public static final int searchLineNumber( + int[] startLineIndexes, + int position) { + // this code is completely useless, but it is the same implementation than + // org.eclipse.jdt.internal.compiler.problem.ProblemHandler.searchLineNumber(int[], int) + // if (startLineIndexes == null) + // return 1; + int length = startLineIndexes.length; + if (length == 0) + return 1; + int g = 0, d = length - 1; + int m = 0; + while (g <= d) { + m = (g + d) / 2; + if (position < startLineIndexes[m]) { + d = m - 1; + } else + if (position > startLineIndexes[m]) { + g = m + 1; + } else { + return m + 1; + } + } + if (position < startLineIndexes[m]) { + return m + 1; + } + return m + 2; + } + + /** + * INTERNAL USE-ONLY + * This methods leaves the space for method counts recording. + */ + public void setForMethodInfos() { + // leave some space for the methodCount + methodCountOffset = contentsOffset; + contentsOffset += 2; + } + + /** + * INTERNAL USE-ONLY + * 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 output directory + * @param relativeFileName java.lang.String + * @param contents byte[] + * + */ + public static void writeToDisk( + boolean generatePackagesStructure, + String outputPath, + String relativeFileName, + byte[] contents) + throws IOException { + + BufferedOutputStream output = null; + if (generatePackagesStructure) { + output = new BufferedOutputStream( + 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); + } + } + output = new BufferedOutputStream( + new FileOutputStream( + new File(fileName))); + } + try { + output.write(contents); + } finally { + output.flush(); + output.close(); + } + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/CompilationResult.java b/src/java/org/eclipse/jdt/internal/compiler/CompilationResult.java new file mode 100644 index 0000000..684df0b --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/CompilationResult.java @@ -0,0 +1,427 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler; + +/** + * A compilation result consists of all information returned by the compiler for + * a single compiled compilation source unit. This includes: + * + * + * The principle structure and binary may be null if the compiler could not produce them. + * If neither could be produced, there is no corresponding entry for the type. + * + * The dependency info includes type references such as supertypes, field types, method + * parameter and return types, local variable types, types of intermediate expressions, etc. + * It also includes the namespaces (packages) in which names were looked up. + * It does not include finer grained dependencies such as information about + * specific fields and methods which were referenced, but does contain their + * declaring types and any other types used to locate such fields or methods. + */ + +import org.eclipse.jdt.core.compiler.*; +import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; +import org.eclipse.jdt.internal.compiler.env.*; +import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; + +import java.util.*; + +public class CompilationResult { + + public IProblem problems[]; + public IProblem tasks[]; + public int problemCount; + public int taskCount; + public ICompilationUnit compilationUnit; + private Map problemsMap; + private Map firstErrorsMap; + private int maxProblemPerUnit; + public char[][][] qualifiedReferences; + public char[][] simpleNameReferences; + + public int lineSeparatorPositions[]; + public Hashtable compiledTypes = new Hashtable(11); + public int unitIndex, totalUnitsKnown; + public boolean hasBeenAccepted = false; + public char[] fileName; + + public CompilationResult( + char[] fileName, + int unitIndex, + int totalUnitsKnown, + int maxProblemPerUnit){ + + this.fileName = fileName; + this.unitIndex = unitIndex; + this.totalUnitsKnown = totalUnitsKnown; + this.maxProblemPerUnit = maxProblemPerUnit; + } + + public CompilationResult( + ICompilationUnit compilationUnit, + int unitIndex, + int totalUnitsKnown, + int maxProblemPerUnit){ + + this.fileName = compilationUnit.getFileName(); + this.compilationUnit = compilationUnit; + this.unitIndex = unitIndex; + this.totalUnitsKnown = totalUnitsKnown; + this.maxProblemPerUnit = maxProblemPerUnit; + } + + private int computePriority(IProblem problem){ + + final int P_STATIC = 10000; + final int P_OUTSIDE_METHOD = 40000; + final int P_FIRST_ERROR = 20000; + final int P_ERROR = 100000; + + int priority = 10000 - problem.getSourceLineNumber(); // early problems first + if (priority < 0) priority = 0; + if (problem.isError()){ + priority += P_ERROR; + } + ReferenceContext context = problemsMap == null ? null : (ReferenceContext) problemsMap.get(problem); + if (context != null){ + if (context instanceof AbstractMethodDeclaration){ + AbstractMethodDeclaration method = (AbstractMethodDeclaration) context; + if (method.isStatic()) { + priority += P_STATIC; + } + } else { + priority += P_OUTSIDE_METHOD; + } + } else { + priority += P_OUTSIDE_METHOD; + } + if (firstErrorsMap.containsKey(problem)){ + priority += P_FIRST_ERROR; + } + return priority; + } + + + public IProblem[] getAllProblems() { + IProblem[] onlyProblems = this.getProblems(); + int onlyProblemCount = onlyProblems != null ? onlyProblems.length : 0; + IProblem[] onlyTasks = this.getTasks(); + int onlyTaskCount = onlyTasks != null ? onlyTasks.length : 0; + if (onlyTaskCount == 0) { + return onlyProblems; + } + if (onlyProblemCount == 0) { + return onlyTasks; + } + + int totalNumberOfProblem = onlyProblemCount + onlyTaskCount; + IProblem[] allProblems = new IProblem[totalNumberOfProblem]; + int allProblemIndex = 0; + int taskIndex = 0; + int problemIndex = 0; + while (taskIndex + problemIndex < totalNumberOfProblem) { + IProblem nextTask = null; + IProblem nextProblem = null; + if (taskIndex < onlyTaskCount) { + nextTask = onlyTasks[taskIndex]; + } + if (problemIndex < onlyProblemCount) { + nextProblem = onlyProblems[problemIndex]; + } + // select the next problem + IProblem currentProblem = null; + if (nextProblem != null) { + if (nextTask != null) { + if (nextProblem.getSourceStart() < nextTask.getSourceStart()) { + currentProblem = nextProblem; + problemIndex++; + } else { + currentProblem = nextTask; + taskIndex++; + } + } else { + currentProblem = nextProblem; + problemIndex++; + } + } else { + if (nextTask != null) { + currentProblem = nextTask; + taskIndex++; + } + } + allProblems[allProblemIndex++] = currentProblem; + } + return allProblems; + } + + public ClassFile[] getClassFiles() { + Enumeration files = compiledTypes.elements(); + ClassFile[] classFiles = new ClassFile[compiledTypes.size()]; + int index = 0; + while (files.hasMoreElements()){ + classFiles[index++] = (ClassFile)files.nextElement(); + } + return classFiles; + } + + /** + * Answer the initial compilation unit corresponding to the present compilation result + */ + public ICompilationUnit getCompilationUnit(){ + return compilationUnit; + } + + /** + * Answer the initial file name + */ + public char[] getFileName(){ + return fileName; + } + + /** + * Answer the errors encountered during compilation. + */ + public IProblem[] getErrors() { + + IProblem[] reportedProblems = getProblems(); + int errorCount = 0; + for (int i = 0; i < this.problemCount; i++) { + if (reportedProblems[i].isError()) errorCount++; + } + if (errorCount == this.problemCount) return reportedProblems; + IProblem[] errors = new IProblem[errorCount]; + int index = 0; + for (int i = 0; i < this.problemCount; i++) { + if (reportedProblems[i].isError()) errors[index++] = reportedProblems[i]; + } + return errors; + } + + /** + * Answer the problems (errors and warnings) encountered during compilation. + * + * This is not a compiler internal API - it has side-effects ! + * It is intended to be used only once all problems have been detected, + * and makes sure the problems slot as the exact size of the number of + * problems. + */ + public IProblem[] getProblems() { + + // Re-adjust the size of the problems if necessary. + if (problems != null) { + + if (this.problemCount != problems.length) { + System.arraycopy(problems, 0, (problems = new IProblem[problemCount]), 0, problemCount); + } + + if (this.maxProblemPerUnit > 0 && this.problemCount > this.maxProblemPerUnit){ + quickPrioritize(problems, 0, problemCount - 1); + this.problemCount = this.maxProblemPerUnit; + System.arraycopy(problems, 0, (problems = new IProblem[problemCount]), 0, problemCount); + } + + // Sort problems per source positions. + quickSort(problems, 0, problems.length-1); + } + return problems; + } + + /** + * Answer the tasks (TO-DO, ...) encountered during compilation. + * + * This is not a compiler internal API - it has side-effects ! + * It is intended to be used only once all problems have been detected, + * and makes sure the problems slot as the exact size of the number of + * problems. + */ + public IProblem[] getTasks() { + + // Re-adjust the size of the tasks if necessary. + if (this.tasks != null) { + + if (this.taskCount != this.tasks.length) { + System.arraycopy(this.tasks, 0, (this.tasks = new IProblem[this.taskCount]), 0, this.taskCount); + } + quickSort(tasks, 0, tasks.length-1); + } + return this.tasks; + } + + public boolean hasErrors() { + + if (problems != null) + for (int i = 0; i < problemCount; i++) { + if (problems[i].isError()) + return true; + } + return false; + } + + public boolean hasProblems() { + + return problemCount != 0; + } + + public boolean hasSyntaxError(){ + + if (problems != null) + for (int i = 0; i < problemCount; i++) { + IProblem problem = problems[i]; + if ((problem.getID() & IProblem.Syntax) != 0 && problem.isError()) + return true; + } + return false; + } + + public boolean hasTasks() { + return this.taskCount != 0; + } + + public boolean hasWarnings() { + + if (problems != null) + for (int i = 0; i < problemCount; i++) { + if (problems[i].isWarning()) + return true; + } + return false; + } + + private static void quickSort(IProblem[] list, int left, int right) { + + if (left >= right) return; + + // sort the problems by their source start position... starting with 0 + int original_left = left; + int original_right = right; + int mid = list[(left + right) / 2].getSourceStart(); + do { + while (list[left].getSourceStart() < mid) + left++; + while (mid < list[right].getSourceStart()) + right--; + if (left <= right) { + IProblem tmp = list[left]; + list[left] = list[right]; + list[right] = tmp; + left++; + right--; + } + } while (left <= right); + if (original_left < right) + quickSort(list, original_left, right); + if (left < original_right) + quickSort(list, left, original_right); + } + + private void quickPrioritize(IProblem[] list, int left, int right) { + + if (left >= right) return; + + // sort the problems by their priority... starting with the highest priority + int original_left = left; + int original_right = right; + int mid = computePriority(list[(left + right) / 2]); + do { + while (computePriority(list[right]) < mid) + right--; + while (mid < computePriority(list[left])) + left++; + if (left <= right) { + IProblem tmp = list[left]; + list[left] = list[right]; + list[right] = tmp; + left++; + right--; + } + } while (left <= right); + if (original_left < right) + quickPrioritize(list, original_left, right); + if (left < original_right) + quickPrioritize(list, left, original_right); + } + + /** + * For now, remember the compiled type using its compound name. + */ + public void record(char[] typeName, ClassFile classFile) { + + compiledTypes.put(typeName, classFile); + } + + public void record(IProblem newProblem, ReferenceContext referenceContext) { + + if (newProblem.getID() == IProblem.Task) { + recordTask(newProblem); + return; + } + if (problemCount == 0) { + problems = new IProblem[5]; + } else if (problemCount == problems.length) { + System.arraycopy(problems, 0, (problems = new IProblem[problemCount * 2]), 0, problemCount); + } + problems[problemCount++] = newProblem; + if (referenceContext != null){ + if (problemsMap == null) problemsMap = new Hashtable(5); + if (firstErrorsMap == null) firstErrorsMap = new Hashtable(5); + if (newProblem.isError() && !referenceContext.hasErrors()) firstErrorsMap.put(newProblem, newProblem); + problemsMap.put(newProblem, referenceContext); + } + } + + private void recordTask(IProblem newProblem) { + if (this.taskCount == 0) { + this.tasks = new IProblem[5]; + } else if (this.taskCount == this.tasks.length) { + System.arraycopy(this.tasks, 0, (this.tasks = new IProblem[this.taskCount * 2]), 0, this.taskCount); + } + this.tasks[this.taskCount++] = newProblem; + } + + public CompilationResult tagAsAccepted(){ + + this.hasBeenAccepted = true; + this.problemsMap = null; // flush + return this; + } + + public String toString(){ + + StringBuffer buffer = new StringBuffer(); + if (this.fileName != null){ + buffer.append("Filename : ").append(this.fileName).append('\n'); //$NON-NLS-1$ + } + if (this.compiledTypes != null){ + buffer.append("COMPILED type(s) \n"); //$NON-NLS-1$ + Enumeration typeNames = this.compiledTypes.keys(); + while (typeNames.hasMoreElements()) { + char[] typeName = (char[]) typeNames.nextElement(); + buffer.append("\t - ").append(typeName).append('\n'); //$NON-NLS-1$ + + } + } else { + buffer.append("No COMPILED type\n"); //$NON-NLS-1$ + } + if (problems != null){ + buffer.append(this.problemCount).append(" PROBLEM(s) detected \n"); //$NON-NLS-1$//$NON-NLS-2$ + for (int i = 0; i < this.problemCount; i++){ + buffer.append("\t - ").append(this.problems[i]).append('\n'); //$NON-NLS-1$ + } + } else { + buffer.append("No PROBLEM\n"); //$NON-NLS-1$ + } + return buffer.toString(); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/Compiler.java b/src/java/org/eclipse/jdt/internal/compiler/Compiler.java new file mode 100644 index 0000000..92c85dc --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/Compiler.java @@ -0,0 +1,610 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler; + +import org.eclipse.jdt.core.compiler.*; +import org.eclipse.jdt.internal.compiler.env.*; +import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.ast.*; +import org.eclipse.jdt.internal.compiler.lookup.*; +import org.eclipse.jdt.internal.compiler.parser.*; +import org.eclipse.jdt.internal.compiler.problem.*; +import org.eclipse.jdt.internal.compiler.util.*; + +import java.io.*; +import java.util.*; + +public class Compiler implements ITypeRequestor, ProblemSeverities { + public Parser parser; + public ICompilerRequestor requestor; + public CompilerOptions options; + public ProblemReporter problemReporter; + + // management of unit to be processed + //public CompilationUnitResult currentCompilationUnitResult; + public CompilationUnitDeclaration[] unitsToProcess; + public int totalUnits; // (totalUnits-1) gives the last unit in unitToProcess + + // name lookup + public LookupEnvironment lookupEnvironment; + + // ONCE STABILIZED, THESE SHOULD RETURN TO A FINAL FIELD + public static boolean DEBUG = false; + public int parseThreshold = -1; + // number of initial units parsed at once (-1: none) + + /* + * Static requestor reserved to listening compilation results in debug mode, + * so as for example to monitor compiler activity independantly from a particular + * builder implementation. It is reset at the end of compilation, and should not + * persist any information after having been reset. + */ + public static IDebugRequestor DebugRequestor = null; + + /** + * Answer a new compiler using the given name environment and compiler options. + * The environment and options will be in effect for the lifetime of the compiler. + * When the compiler is run, compilation results are sent to the given requestor. + * + * @param environment org.eclipse.jdt.internal.compiler.api.env.INameEnvironment + * Environment used by the compiler in order to resolve type and package + * names. The name environment implements the actual connection of the compiler + * to the outside world (e.g. in batch mode the name environment is performing + * pure file accesses, reuse previous build state or connection to repositories). + * Note: the name environment is responsible for implementing the actual classpath + * rules. + * + * @param policy org.eclipse.jdt.internal.compiler.api.problem.IErrorHandlingPolicy + * Configurable part for problem handling, allowing the compiler client to + * specify the rules for handling problems (stop on first error or accumulate + * them all) and at the same time perform some actions such as opening a dialog + * in UI when compiling interactively. + * @see org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies + * + * @param requestor org.eclipse.jdt.internal.compiler.api.ICompilerRequestor + * Component which will receive and persist all compilation results and is intended + * to consume them as they are produced. Typically, in a batch compiler, it is + * responsible for writing out the actual .class files to the file system. + * @see org.eclipse.jdt.internal.compiler.CompilationResult + * + * @param problemFactory org.eclipse.jdt.internal.compiler.api.problem.IProblemFactory + * Factory used inside the compiler to create problem descriptors. It allows the + * compiler client to supply its own representation of compilation problems in + * order to avoid object conversions. Note that the factory is not supposed + * to accumulate the created problems, the compiler will gather them all and hand + * them back as part of the compilation unit result. + */ + public Compiler( + INameEnvironment environment, + IErrorHandlingPolicy policy, + Map settings, + final ICompilerRequestor requestor, + IProblemFactory problemFactory) { + + // create a problem handler given a handling policy + this.options = new CompilerOptions(settings); + + // wrap requestor in DebugRequestor if one is specified + if(DebugRequestor == null) { + this.requestor = requestor; + } else { + this.requestor = new ICompilerRequestor(){ + public void acceptResult(CompilationResult result){ + if (DebugRequestor.isActive()){ + DebugRequestor.acceptDebugResult(result); + } + requestor.acceptResult(result); + } + }; + } + this.problemReporter = + new ProblemReporter(policy, this.options, problemFactory); + this.lookupEnvironment = + new LookupEnvironment(this, options, problemReporter, environment); + initializeParser(); + } + + /** + * Answer a new compiler using the given name environment and compiler options. + * The environment and options will be in effect for the lifetime of the compiler. + * When the compiler is run, compilation results are sent to the given requestor. + * + * @param environment org.eclipse.jdt.internal.compiler.api.env.INameEnvironment + * Environment used by the compiler in order to resolve type and package + * names. The name environment implements the actual connection of the compiler + * to the outside world (e.g. in batch mode the name environment is performing + * pure file accesses, reuse previous build state or connection to repositories). + * Note: the name environment is responsible for implementing the actual classpath + * rules. + * + * @param policy org.eclipse.jdt.internal.compiler.api.problem.IErrorHandlingPolicy + * Configurable part for problem handling, allowing the compiler client to + * specify the rules for handling problems (stop on first error or accumulate + * them all) and at the same time perform some actions such as opening a dialog + * in UI when compiling interactively. + * @see org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies + * + * @param requestor org.eclipse.jdt.internal.compiler.api.ICompilerRequestor + * Component which will receive and persist all compilation results and is intended + * to consume them as they are produced. Typically, in a batch compiler, it is + * responsible for writing out the actual .class files to the file system. + * @see org.eclipse.jdt.internal.compiler.CompilationResult + * + * @param problemFactory org.eclipse.jdt.internal.compiler.api.problem.IProblemFactory + * Factory used inside the compiler to create problem descriptors. It allows the + * compiler client to supply its own representation of compilation problems in + * order to avoid object conversions. Note that the factory is not supposed + * to accumulate the created problems, the compiler will gather them all and hand + * them back as part of the compilation unit result. + * @param parseLiteralExpressionsAsConstants boolean + * This parameter is used to optimize the literals or leave them as they are in the source. + * If you put true, "Hello" + " world" will be converted to "Hello world". + */ + public Compiler( + INameEnvironment environment, + IErrorHandlingPolicy policy, + Map settings, + final ICompilerRequestor requestor, + IProblemFactory problemFactory, + boolean parseLiteralExpressionsAsConstants) { + + // create a problem handler given a handling policy + this.options = new CompilerOptions(settings); + + // wrap requestor in DebugRequestor if one is specified + if(DebugRequestor == null) { + this.requestor = requestor; + } else { + this.requestor = new ICompilerRequestor(){ + public void acceptResult(CompilationResult result){ + if (DebugRequestor.isActive()){ + DebugRequestor.acceptDebugResult(result); + } + requestor.acceptResult(result); + } + }; + } + this.problemReporter = new ProblemReporter(policy, this.options, problemFactory); + this.lookupEnvironment = new LookupEnvironment(this, options, problemReporter, environment); + initializeParser(); + } + + /** + * Add an additional binary type + */ + public void accept(IBinaryType binaryType, PackageBinding packageBinding) { + if (options.verbose) { + System.out.println( + Util.bind( + "compilation.loadBinary" , //$NON-NLS-1$ + new String[] { + new String(binaryType.getName())})); +// new Exception("TRACE BINARY").printStackTrace(System.out); +// System.out.println(); + } + lookupEnvironment.createBinaryTypeFrom(binaryType, packageBinding); + } + + /** + * Add an additional compilation unit into the loop + * -> build compilation unit declarations, their bindings and record their results. + */ + public void accept(ICompilationUnit sourceUnit) { + // Switch the current policy and compilation result for this unit to the requested one. + CompilationResult unitResult = + new CompilationResult(sourceUnit, totalUnits, totalUnits, this.options.maxProblemsPerUnit); + try { + if (options.verbose) { + String count = String.valueOf(totalUnits + 1); + System.out.println( + Util.bind( + "compilation.request" , //$NON-NLS-1$ + new String[] { + count, + count, + new String(sourceUnit.getFileName())})); + } + // diet parsing for large collection of unit + CompilationUnitDeclaration parsedUnit; + if (totalUnits < parseThreshold) { + parsedUnit = parser.parse(sourceUnit, unitResult); + } else { + parsedUnit = parser.dietParse(sourceUnit, unitResult); + } + // initial type binding creation + lookupEnvironment.buildTypeBindings(parsedUnit); + this.addCompilationUnit(sourceUnit, parsedUnit); + + // binding resolution + lookupEnvironment.completeTypeBindings(parsedUnit); + } catch (AbortCompilationUnit e) { + // at this point, currentCompilationUnitResult may not be sourceUnit, but some other + // one requested further along to resolve sourceUnit. + if (unitResult.compilationUnit == sourceUnit) { // only report once + requestor.acceptResult(unitResult.tagAsAccepted()); + } else { + throw e; // want to abort enclosing request to compile + } + } + } + + /** + * Add additional source types + */ + public void accept(ISourceType[] sourceTypes, PackageBinding packageBinding) { + problemReporter.abortDueToInternalError( + Util.bind( + "abort.againstSourceModel" , //$NON-NLS-1$ + String.valueOf(sourceTypes[0].getName()), + String.valueOf(sourceTypes[0].getFileName()))); + } + + protected void addCompilationUnit( + ICompilationUnit sourceUnit, + CompilationUnitDeclaration parsedUnit) { + + // append the unit to the list of ones to process later on + int size = unitsToProcess.length; + if (totalUnits == size) + // when growing reposition units starting at position 0 + System.arraycopy( + unitsToProcess, + 0, + (unitsToProcess = new CompilationUnitDeclaration[size * 2]), + 0, + totalUnits); + unitsToProcess[totalUnits++] = parsedUnit; + } + + /** + * Add the initial set of compilation units into the loop + * -> build compilation unit declarations, their bindings and record their results. + */ + protected void beginToCompile(ICompilationUnit[] sourceUnits) { + int maxUnits = sourceUnits.length; + totalUnits = 0; + unitsToProcess = new CompilationUnitDeclaration[maxUnits]; + + // Switch the current policy and compilation result for this unit to the requested one. + for (int i = 0; i < maxUnits; i++) { + CompilationUnitDeclaration parsedUnit; + CompilationResult unitResult = + new CompilationResult(sourceUnits[i], i, maxUnits, this.options.maxProblemsPerUnit); + try { + if (options.verbose) { + System.out.println( + Util.bind( + "compilation.request" , //$NON-NLS-1$ + new String[] { + String.valueOf(i + 1), + String.valueOf(maxUnits), + new String(sourceUnits[i].getFileName())})); + } + // diet parsing for large collection of units + if (totalUnits < parseThreshold) { + parsedUnit = parser.parse(sourceUnits[i], unitResult); + } else { + parsedUnit = parser.dietParse(sourceUnits[i], unitResult); + } + // initial type binding creation + lookupEnvironment.buildTypeBindings(parsedUnit); + this.addCompilationUnit(sourceUnits[i], parsedUnit); + //} catch (AbortCompilationUnit e) { + // requestor.acceptResult(unitResult.tagAsAccepted()); + } finally { + sourceUnits[i] = null; // no longer hold onto the unit + } + } + // binding resolution + lookupEnvironment.completeTypeBindings(); + } + + /** + * General API + * -> compile each of supplied files + * -> recompile any required types for which we have an incomplete principle structure + */ + public void compile(ICompilationUnit[] sourceUnits) { + CompilationUnitDeclaration unit = null; + int i = 0; + try { + // build and record parsed units + + beginToCompile(sourceUnits); + + // process all units (some more could be injected in the loop by the lookup environment) + for (; i < totalUnits; i++) { + unit = unitsToProcess[i]; + try { + if (options.verbose) + System.out.println( + Util.bind( + "compilation.process" , //$NON-NLS-1$ + new String[] { + String.valueOf(i + 1), + String.valueOf(totalUnits), + new String(unitsToProcess[i].getFileName())})); + process(unit, i); + } finally { + // cleanup compilation unit result + unit.cleanUp(); + } + unitsToProcess[i] = null; // release reference to processed unit declaration + requestor.acceptResult(unit.compilationResult.tagAsAccepted()); + if (options.verbose) + System.out.println(Util.bind("compilation.done", //$NON-NLS-1$ + new String[] { + String.valueOf(i + 1), + String.valueOf(totalUnits), + new String(unit.getFileName())})); + } + } catch (AbortCompilation e) { + this.handleInternalException(e, unit); + } catch (Error e) { + this.handleInternalException(e, unit, null); + throw e; // rethrow + } catch (RuntimeException e) { + this.handleInternalException(e, unit, null); + throw e; // rethrow + } finally { + this.reset(); + } + if (options.verbose) { + if (totalUnits > 1) { + System.out.println( + Util.bind("compilation.units" , String.valueOf(totalUnits))); //$NON-NLS-1$ + } else { + System.out.println( + Util.bind("compilation.unit" , String.valueOf(totalUnits))); //$NON-NLS-1$ + } + } + } + + /* + * Compiler crash recovery in case of unexpected runtime exceptions + */ + protected void handleInternalException( + Throwable internalException, + CompilationUnitDeclaration unit, + CompilationResult result) { + + /* find a compilation result */ + if ((unit != null)) // basing result upon the current unit if available + result = unit.compilationResult; // current unit being processed ? + if ((result == null) && (unitsToProcess != null) && (totalUnits > 0)) + result = unitsToProcess[totalUnits - 1].compilationResult; + // last unit in beginToCompile ? + + boolean needToPrint = true; + if (result != null) { + /* create and record a compilation problem */ + StringWriter stringWriter = new StringWriter(); + PrintWriter writer = new PrintWriter(stringWriter); + internalException.printStackTrace(writer); + StringBuffer buffer = stringWriter.getBuffer(); + + String[] pbArguments = new String[] { + Util.bind("compilation.internalError" ) //$NON-NLS-1$ + + "\n" //$NON-NLS-1$ + + buffer.toString()}; + + result + .record( + problemReporter + .createProblem( + result.getFileName(), + IProblem.Unclassified, + pbArguments, + pbArguments, + Error, // severity + 0, // source start + 0, // source end + 0), // line number + unit); + + /* hand back the compilation result */ + if (!result.hasBeenAccepted) { + requestor.acceptResult(result.tagAsAccepted()); + needToPrint = false; + } + } + if (needToPrint) { + /* dump a stack trace to the console */ + internalException.printStackTrace(); + } + } + + /* + * Compiler recovery in case of internal AbortCompilation event + */ + protected void handleInternalException( + AbortCompilation abortException, + CompilationUnitDeclaration unit) { + + /* special treatment for SilentAbort: silently cancelling the compilation process */ + if (abortException.isSilent) { + if (abortException.silentException == null) { + return; + } + throw abortException.silentException; + } + + /* uncomment following line to see where the abort came from */ + // abortException.printStackTrace(); + + // Exception may tell which compilation result it is related, and which problem caused it + CompilationResult result = abortException.compilationResult; + if ((result == null) && (unit != null)) { + result = unit.compilationResult; // current unit being processed ? + } + // Lookup environment may be in middle of connecting types + if ((result == null) && lookupEnvironment.unitBeingCompleted != null) { + result = lookupEnvironment.unitBeingCompleted.compilationResult; + } + if ((result == null) && (unitsToProcess != null) && (totalUnits > 0)) + result = unitsToProcess[totalUnits - 1].compilationResult; + // last unit in beginToCompile ? + if (result != null && !result.hasBeenAccepted) { + /* distant problem which could not be reported back there? */ + if (abortException.problem != null) { + recordDistantProblem: { + IProblem distantProblem = abortException.problem; + IProblem[] knownProblems = result.problems; + for (int i = 0; i < result.problemCount; i++) { + if (knownProblems[i] == distantProblem) { // already recorded + break recordDistantProblem; + } + } + if (distantProblem instanceof DefaultProblem) { // fixup filename TODO (philippe) should improve API to make this official + ((DefaultProblem) distantProblem).setOriginatingFileName(result.getFileName()); + } + result .record(distantProblem, unit); + } + } else { + /* distant internal exception which could not be reported back there */ + if (abortException.exception != null) { + this.handleInternalException(abortException.exception, null, result); + return; + } + } + /* hand back the compilation result */ + if (!result.hasBeenAccepted) { + requestor.acceptResult(result.tagAsAccepted()); + } + } else { + abortException.printStackTrace(); + } + } + + public void initializeParser() { + + this.parser = new Parser(this.problemReporter, this.options.parseLiteralExpressionsAsConstants); + } + + /** + * Process a compilation unit already parsed and build. + */ + public void process(CompilationUnitDeclaration unit, int i) { + + this.parser.getMethodBodies(unit); + + // fault in fields & methods + if (unit.scope != null) + unit.scope.faultInTypes(); + + // verify inherited methods + if (unit.scope != null) + unit.scope.verifyMethods(lookupEnvironment.methodVerifier()); + + // type checking + unit.resolve(); + + // flow analysis + unit.analyseCode(); + + // code generation + unit.generateCode(); + + // reference info + if (options.produceReferenceInfo && unit.scope != null) + unit.scope.storeDependencyInfo(); + + // refresh the total number of units known at this stage + unit.compilationResult.totalUnitsKnown = totalUnits; + } + public void reset() { + lookupEnvironment.reset(); + parser.scanner.source = null; + unitsToProcess = null; + if (DebugRequestor != null) DebugRequestor.reset(); + } + + /** + * Internal API used to resolve a given compilation unit. Can run a subset of the compilation process + */ + public CompilationUnitDeclaration resolve( + CompilationUnitDeclaration unit, + ICompilationUnit sourceUnit, + boolean verifyMethods, + boolean analyzeCode, + boolean generateCode) { + + try { + if (unit == null) { + // build and record parsed units + parseThreshold = 0; // will request a full parse + beginToCompile(new ICompilationUnit[] { sourceUnit }); + // process all units (some more could be injected in the loop by the lookup environment) + unit = unitsToProcess[0]; + } else { + // initial type binding creation + lookupEnvironment.buildTypeBindings(unit); + + // binding resolution + lookupEnvironment.completeTypeBindings(); + } + this.parser.getMethodBodies(unit); + if (unit.scope != null) { + // fault in fields & methods + unit.scope.faultInTypes(); + if (unit.scope != null && verifyMethods) { + // http://dev.eclipse.org/bugs/show_bug.cgi?id=23117 + // verify inherited methods + unit.scope.verifyMethods(lookupEnvironment.methodVerifier()); + } + // type checking + unit.resolve(); + + // flow analysis + if (analyzeCode) unit.analyseCode(); + + // code generation + if (generateCode) unit.generateCode(); + } + if (unitsToProcess != null) unitsToProcess[0] = null; // release reference to processed unit declaration + requestor.acceptResult(unit.compilationResult.tagAsAccepted()); + return unit; + } catch (AbortCompilation e) { + this.handleInternalException(e, unit); + return unit == null ? unitsToProcess[0] : unit; + } catch (Error e) { + this.handleInternalException(e, unit, null); + throw e; // rethrow + } catch (RuntimeException e) { + this.handleInternalException(e, unit, null); + throw e; // rethrow + } finally { + // No reset is performed there anymore since, + // within the CodeAssist (or related tools), + // the compiler may be called *after* a call + // to this resolve(...) method. And such a call + // needs to have a compiler with a non-empty + // environment. + // this.reset(); + } + } + /** + * Internal API used to resolve a given compilation unit. Can run a subset of the compilation process + */ + public CompilationUnitDeclaration resolve( + ICompilationUnit sourceUnit, + boolean verifyMethods, + boolean analyzeCode, + boolean generateCode) { + + return resolve( + null, + sourceUnit, + verifyMethods, + analyzeCode, + generateCode); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ConfigurableOption.java b/src/java/org/eclipse/jdt/internal/compiler/ConfigurableOption.java new file mode 100644 index 0000000..13e2858 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ConfigurableOption.java @@ -0,0 +1,227 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler; + +/** + * Generic option description, which can be modified independently from the + * component it belongs to. + * + * @deprecated backport 1.0 internal functionality + */ + +import java.util.*; + +public class ConfigurableOption { + private String componentName; + private String optionName; + private int id; + + private String category; + private String name; + private String description; + private int currentValueIndex; + private int defaultValueIndex; + private String[] possibleValues; + + // special value for indicating that + // the is the actual value + public final static String[] NoDiscreteValue = {}; +/** + * INTERNAL USE ONLY + * + * Initialize an instance of this class according to a specific locale + * + * @param loc java.util.Locale + */ +public ConfigurableOption( + String componentName, + String optionName, + Locale loc, + int currentValueIndex) { + + this.componentName = componentName; + this.optionName = optionName; + this.currentValueIndex = currentValueIndex; + + ResourceBundle resource = null; + try { + String location = componentName.substring(0, componentName.lastIndexOf('.')); + resource = ResourceBundle.getBundle(location + ".options", loc); //$NON-NLS-1$ + } catch (MissingResourceException e) { + category = "Missing ressources entries for" + componentName + " options"; //$NON-NLS-1$ //$NON-NLS-2$ + name = "Missing ressources entries for"+ componentName + " options"; //$NON-NLS-1$ //$NON-NLS-2$ + description = "Missing ressources entries for" + componentName + " options"; //$NON-NLS-1$ //$NON-NLS-2$ + possibleValues = new String[0]; + id = -1; + } + if (resource == null) return; + try { + id = Integer.parseInt(resource.getString(optionName + ".number")); //$NON-NLS-1$ + } catch (MissingResourceException e) { + id = -1; + } catch (NumberFormatException e) { + id = -1; + } + try { + category = resource.getString(optionName + ".category"); //$NON-NLS-1$ + } catch (MissingResourceException e) { + category = "Missing ressources entries for" + componentName + " options"; //$NON-NLS-1$ //$NON-NLS-2$ + } + try { + name = resource.getString(optionName + ".name"); //$NON-NLS-1$ + } catch (MissingResourceException e) { + name = "Missing ressources entries for"+ componentName + " options"; //$NON-NLS-1$ //$NON-NLS-2$ + } + try { + StringTokenizer tokenizer = new StringTokenizer(resource.getString(optionName + ".possibleValues"), "|"); //$NON-NLS-1$ //$NON-NLS-2$ + int numberOfValues = Integer.parseInt(tokenizer.nextToken()); + if(numberOfValues == -1){ + possibleValues = NoDiscreteValue; + } else { + possibleValues = new String[numberOfValues]; + int index = 0; + while (tokenizer.hasMoreTokens()) { + possibleValues[index] = tokenizer.nextToken(); + index++; + } + } + } catch (MissingResourceException e) { + possibleValues = new String[0]; + } catch (NoSuchElementException e) { + possibleValues = new String[0]; + } catch (NumberFormatException e) { + possibleValues = new String[0]; + } + try { + description = resource.getString(optionName + ".description"); //$NON-NLS-1$ + } catch (MissingResourceException e) { + description = "Missing ressources entries for"+ componentName + " options"; //$NON-NLS-1$ //$NON-NLS-2$ + } +} +/** + * Return a String that represents the localized category of the receiver. + * @return java.lang.String + */ +public String getCategory() { + return category; +} +/** + * Return a String that identifies the component owner (typically the qualified + * type name of the class which it corresponds to). + * + * e.g. "org.eclipse.jdt.internal.compiler.api.Compiler" + * + * @return java.lang.String + */ +public String getComponentName() { + return componentName; +} +/** + * Answer the index (in possibleValues array) of the current setting for this + * particular option. + * + * In case the set of possibleValues is NoDiscreteValue, then this index is the + * actual value (e.g. max line lenght set to 80). + * + * @return int + */ +public int getCurrentValueIndex() { + return currentValueIndex; +} +/** + * Answer the index (in possibleValues array) of the default setting for this + * particular option. + * + * In case the set of possibleValues is NoDiscreteValue, then this index is the + * actual value (e.g. max line lenght set to 80). + * + * @return int + */ +public int getDefaultValueIndex() { + return defaultValueIndex; +} +/** + * Return an String that represents the localized description of the receiver. + * + * @return java.lang.String + */ +public String getDescription() { + return description; +} +/** + * Internal ID which allows the configurable component to identify this particular option. + * + * @return int + */ +public int getID() { + return id; +} +/** + * Return a String that represents the localized name of the receiver. + * @return java.lang.String + */ +public String getName() { + return name; +} +/** + * Return an array of String that represents the localized possible values of the receiver. + * @return java.lang.String[] + */ +public String[] getPossibleValues() { + return possibleValues; +} +/** + * Change the index (in possibleValues array) of the current setting for this + * particular option. + * + * In case the set of possibleValues is NoDiscreteValue, then this index is the + * actual value (e.g. max line lenght set to 80). + */ +public void setValueIndex(int newIndex) { + currentValueIndex = newIndex; +} +public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append("Configurable option for "); //$NON-NLS-1$ + buffer.append(this.componentName).append("\n"); //$NON-NLS-1$ + buffer.append("- category: ").append(this.category).append("\n"); //$NON-NLS-1$ //$NON-NLS-2$ + buffer.append("- name: ").append(this.name).append("\n"); //$NON-NLS-1$ //$NON-NLS-2$ + /* display current value */ + buffer.append("- current value: "); //$NON-NLS-1$ + if (possibleValues == NoDiscreteValue){ + buffer.append(this.currentValueIndex); + } else { + buffer.append(this.possibleValues[this.currentValueIndex]); + } + buffer.append("\n"); //$NON-NLS-1$ + + /* display possible values */ + if (possibleValues != NoDiscreteValue){ + buffer.append("- possible values: ["); //$NON-NLS-1$ + for (int i = 0, max = possibleValues.length; i < max; i++) { + if (i != 0) + buffer.append(", "); //$NON-NLS-1$ + buffer.append(possibleValues[i]); + } + buffer.append("]\n"); //$NON-NLS-1$ + buffer.append("- curr. val. index: ").append(currentValueIndex).append("\n"); //$NON-NLS-1$ //$NON-NLS-2$ + } + buffer.append("- description: ").append(description).append("\n"); //$NON-NLS-1$ //$NON-NLS-2$ + return buffer.toString(); +} + /** + * Gets the optionName. + * @return Returns a String + */ + public String getOptionName() { + return optionName; + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/DefaultErrorHandlingPolicies.java b/src/java/org/eclipse/jdt/internal/compiler/DefaultErrorHandlingPolicies.java new file mode 100644 index 0000000..5036df6 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/DefaultErrorHandlingPolicies.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler; + +public class DefaultErrorHandlingPolicies { + +/* + * Accumulate all problems, then exit without proceeding. + * + * Typically, the #proceedWithProblems(Problem[]) should + * show the problems. + * + */ +public static IErrorHandlingPolicy exitAfterAllProblems() { + return new IErrorHandlingPolicy() { + public boolean stopOnFirstError() { + return false; + } + public boolean proceedOnErrors(){ + return false; + } + }; +} +/* + * Exit without proceeding on the first problem wich appears + * to be an error. + * + */ +public static IErrorHandlingPolicy exitOnFirstError() { + return new IErrorHandlingPolicy() { + public boolean stopOnFirstError() { + return true; + } + public boolean proceedOnErrors(){ + return false; + } + }; +} +/* + * Proceed on the first error met. + * + */ +public static IErrorHandlingPolicy proceedOnFirstError() { + return new IErrorHandlingPolicy() { + public boolean stopOnFirstError() { + return true; + } + public boolean proceedOnErrors(){ + return true; + } + }; +} +/* + * Accumulate all problems, then proceed with them. + * + */ +public static IErrorHandlingPolicy proceedWithAllProblems() { + return new IErrorHandlingPolicy() { + public boolean stopOnFirstError() { + return false; + } + public boolean proceedOnErrors(){ + return true; + } + }; +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ICompilerRequestor.java b/src/java/org/eclipse/jdt/internal/compiler/ICompilerRequestor.java new file mode 100644 index 0000000..0d8d039 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ICompilerRequestor.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler; + +/** + * A callback interface for receiving compilation results. + */ +public interface ICompilerRequestor { + + /** + * Accept a compilation result. + */ + public void acceptResult(CompilationResult result); +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/IDebugRequestor.java b/src/java/org/eclipse/jdt/internal/compiler/IDebugRequestor.java new file mode 100644 index 0000000..31570e3 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/IDebugRequestor.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler; + +public interface IDebugRequestor { + + /* + * Debug callback method allowing to take into account a new compilation result. + * Any side-effect performed on the actual result might interfere with the + * original compiler requestor, and should be prohibited. + */ + void acceptDebugResult(CompilationResult result); + + /* + * Answers true when in active mode + */ + boolean isActive(); + + /* + * Activate debug callbacks + */ + void activate(); + + /* + * Deactivate debug callbacks + */ + void deactivate(); + + /* + * Reset debug requestor after compilation has finished + */ + void reset(); +} + diff --git a/src/java/org/eclipse/jdt/internal/compiler/IErrorHandlingPolicy.java b/src/java/org/eclipse/jdt/internal/compiler/IErrorHandlingPolicy.java new file mode 100644 index 0000000..a585e9f --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/IErrorHandlingPolicy.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler; + +/* + * Handler policy is responsible to answer the 2 following + * questions: + * 1. should the handler stop on first problem which appears + * to be a real error (that is, not a warning), + * 2. should it proceed once it has gathered all problems + * + * The intent is that one can supply its own policy to implement + * some interactive error handling strategy where some UI would + * display problems and ask user if he wants to proceed or not. + */ + +public interface IErrorHandlingPolicy { + boolean proceedOnErrors(); + boolean stopOnFirstError(); +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/IProblemFactory.java b/src/java/org/eclipse/jdt/internal/compiler/IProblemFactory.java new file mode 100644 index 0000000..f5e8d1b --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/IProblemFactory.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler; + +import java.util.Locale; + +import org.eclipse.jdt.core.compiler.*; + +/* + * Factory used from inside the compiler to build the actual problems + * which are handed back in the compilation result. + * + * This allows sharing the internal problem representation with the environment. + * + * Note: The factory is responsible for computing and storing a localized error message. + */ + +public interface IProblemFactory { + + IProblem createProblem( + char[] originatingFileName, + int problemId, + String[] problemArguments, + String[] messageArguments, // shorter versions of the problemArguments + int severity, + int startPosition, + int endPosition, + int lineNumber); + + Locale getLocale(); + + String getLocalizedMessage(int problemId, String[] messageArguments); +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/AND_AND_Expression.java b/src/java/org/eclipse/jdt/internal/compiler/ast/AND_AND_Expression.java new file mode 100644 index 0000000..a8db03f --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/AND_AND_Expression.java @@ -0,0 +1,269 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +//dedicated treatment for the && +public class AND_AND_Expression extends BinaryExpression { + + int rightInitStateIndex = -1; + int mergedInitStateIndex = -1; + + public AND_AND_Expression(Expression left, Expression right, int operator) { + super(left, right, operator); + } + + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + + Constant cst = this.left.optimizedBooleanConstant(); + boolean isLeftOptimizedTrue = cst != NotAConstant && cst.booleanValue() == true; + boolean isLeftOptimizedFalse = cst != NotAConstant && cst.booleanValue() == false; + + if (isLeftOptimizedTrue) { + // TRUE && anything + // need to be careful of scenario: + // (x && y) && !z, if passing the left info to the right, it would + // be swapped by the ! + FlowInfo mergedInfo = left.analyseCode(currentScope, flowContext, flowInfo) + .unconditionalInits(); + mergedInfo = right.analyseCode(currentScope, flowContext, mergedInfo); + mergedInitStateIndex = currentScope.methodScope() + .recordInitializationStates(mergedInfo); + return mergedInfo; + } + + FlowInfo leftInfo = left.analyseCode(currentScope, flowContext, flowInfo); + // need to be careful of scenario: + // (x && y) && !z, if passing the left info to the right, it would be + // swapped by the ! + FlowInfo rightInfo = leftInfo.initsWhenTrue().unconditionalInits().copy(); + rightInitStateIndex = currentScope.methodScope().recordInitializationStates(rightInfo); + + int previousMode = rightInfo.reachMode(); + if (isLeftOptimizedFalse) { + rightInfo.setReachMode(FlowInfo.UNREACHABLE); + } + rightInfo = right.analyseCode(currentScope, flowContext, rightInfo); + FlowInfo trueMergedInfo = rightInfo.initsWhenTrue().copy(); + rightInfo.setReachMode(previousMode); // reset after trueMergedInfo got extracted + FlowInfo mergedInfo = FlowInfo.conditional( + trueMergedInfo, + leftInfo.initsWhenFalse().copy().unconditionalInits().mergedWith( + rightInfo.initsWhenFalse().copy().unconditionalInits())); + mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo); + return mergedInfo; + } + + /** + * Code generation for a binary operation + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { + + int pc = codeStream.position; + if (constant != Constant.NotAConstant) { + // inlined value + if (valueRequired) + codeStream.generateConstant(constant, implicitConversion); + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + Constant cst = right.constant; + if (cst != NotAConstant) { + // && true --> + if (cst.booleanValue() == true) { + this.left.generateCode(currentScope, codeStream, valueRequired); + } else { + // && false --> false + this.left.generateCode(currentScope, codeStream, false); + if (valueRequired) codeStream.iconst_0(); + } + if (mergedInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables(currentScope, mergedInitStateIndex); + } + codeStream.generateImplicitConversion(implicitConversion); + codeStream.updateLastRecordedEndPC(codeStream.position); + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + + Label falseLabel = new Label(codeStream), endLabel; + cst = left.optimizedBooleanConstant(); + boolean leftIsConst = cst != NotAConstant; + boolean leftIsTrue = leftIsConst && cst.booleanValue() == true; + + cst = right.optimizedBooleanConstant(); + boolean rightIsConst = cst != NotAConstant; + boolean rightIsTrue = rightIsConst && cst.booleanValue() == true; + + generateOperands : { + if (leftIsConst) { + left.generateCode(currentScope, codeStream, false); + if (!leftIsTrue) { + break generateOperands; // no need to generate right operand + } + } else { + left.generateOptimizedBoolean(currentScope, codeStream, null, falseLabel, true); + // need value, e.g. if (a == 1 && ((b = 2) > 0)) {} -> shouldn't initialize 'b' if a!=1 + } + if (rightInitStateIndex != -1) { + codeStream.addDefinitelyAssignedVariables(currentScope, rightInitStateIndex); + } + if (rightIsConst) { + right.generateCode(currentScope, codeStream, false); + } else { + right.generateOptimizedBoolean(currentScope, codeStream, null, falseLabel, valueRequired); + } + } + if (mergedInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables(currentScope, mergedInitStateIndex); + } + /* + * improving code gen for such a case: boolean b = i < 0 && false since + * the label has never been used, we have the inlined value on the + * stack. + */ + if (valueRequired) { + if (leftIsConst && !leftIsTrue) { + codeStream.iconst_0(); + codeStream.updateLastRecordedEndPC(codeStream.position); + } else { + if (rightIsConst && !rightIsTrue) { + codeStream.iconst_0(); + codeStream.updateLastRecordedEndPC(codeStream.position); + } else { + codeStream.iconst_1(); + } + if (falseLabel.hasForwardReferences()) { + if ((bits & ValueForReturnMASK) != 0) { + codeStream.ireturn(); + falseLabel.place(); + codeStream.iconst_0(); + } else { + codeStream.goto_(endLabel = new Label(codeStream)); + codeStream.decrStackSize(1); + falseLabel.place(); + codeStream.iconst_0(); + endLabel.place(); + } + } else { + falseLabel.place(); + } + } + codeStream.generateImplicitConversion(implicitConversion); + codeStream.updateLastRecordedEndPC(codeStream.position); + } else { + falseLabel.place(); + } + } + + /** + * Boolean operator code generation Optimized operations are: && + */ + public void generateOptimizedBoolean(BlockScope currentScope, CodeStream codeStream, + Label trueLabel, Label falseLabel, boolean valueRequired) { + + if (constant != Constant.NotAConstant) { + super.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, + valueRequired); + return; + } + + // && true --> + Constant cst = right.constant; + if (cst != NotAConstant && cst.booleanValue() == true) { + int pc = codeStream.position; + this.left.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired); + if (mergedInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables(currentScope, mergedInitStateIndex); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + cst = left.optimizedBooleanConstant(); + boolean leftIsConst = cst != NotAConstant; + boolean leftIsTrue = leftIsConst && cst.booleanValue() == true; + + cst = right.optimizedBooleanConstant(); + boolean rightIsConst = cst != NotAConstant; + boolean rightIsTrue = rightIsConst && cst.booleanValue() == true; + + // default case + generateOperands : { + if (falseLabel == null) { + if (trueLabel != null) { + // implicit falling through the FALSE case + Label internalFalseLabel = new Label(codeStream); + left.generateOptimizedBoolean(currentScope, codeStream, null, + internalFalseLabel, !leftIsConst); + // need value, e.g. if (a == 1 && ((b = 2) > 0)) {} -> shouldn't initialize 'b' if a!=1 + if (leftIsConst && !leftIsTrue) { + internalFalseLabel.place(); + break generateOperands; // no need to generate right operand + } + if (rightInitStateIndex != -1) { + codeStream + .addDefinitelyAssignedVariables(currentScope, rightInitStateIndex); + } + right.generateOptimizedBoolean(currentScope, codeStream, trueLabel, null, + valueRequired && !rightIsConst); + if (valueRequired && rightIsConst && rightIsTrue) { + codeStream.goto_(trueLabel); + codeStream.updateLastRecordedEndPC(codeStream.position); + } + internalFalseLabel.place(); + } + } else { + // implicit falling through the TRUE case + if (trueLabel == null) { + left.generateOptimizedBoolean(currentScope, codeStream, null, falseLabel, !leftIsConst); + // need value, e.g. if (a == 1 && ((b = 2) > 0)) {} -> shouldn't initialize 'b' if a!=1 + if (leftIsConst && !leftIsTrue) { + codeStream.goto_(falseLabel); + codeStream.updateLastRecordedEndPC(codeStream.position); + break generateOperands; // no need to generate right operand + } + if (rightInitStateIndex != -1) { + codeStream + .addDefinitelyAssignedVariables(currentScope, rightInitStateIndex); + } + right.generateOptimizedBoolean(currentScope, codeStream, null, falseLabel, + valueRequired && !rightIsConst); + if (valueRequired && rightIsConst && !rightIsTrue) { + codeStream.goto_(falseLabel); + codeStream.updateLastRecordedEndPC(codeStream.position); + } + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + if (mergedInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables(currentScope, mergedInitStateIndex); + } + } + + public boolean isCompactableOperation() { + return false; + } + + public void traverse(ASTVisitor visitor, BlockScope scope) { + if (visitor.visit(this, scope)) { + left.traverse(visitor, scope); + right.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +} \ No newline at end of file diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/ASTNode.java b/src/java/org/eclipse/jdt/internal/compiler/ast/ASTNode.java new file mode 100644 index 0000000..74ba90b --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/ASTNode.java @@ -0,0 +1,272 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.lookup.*; +import org.eclipse.jdt.internal.compiler.ASTVisitor; + +public abstract class ASTNode implements BaseTypes, CompilerModifiers, TypeConstants, TypeIds { + + public int sourceStart, sourceEnd; + + //some global provision for the hierarchy + public final static Constant NotAConstant = Constant.NotAConstant; + + // storage for internal flags (32 bits) BIT USAGE + public final static int Bit1 = 0x1; // return type (operator) | name reference kind (name ref) | add assertion (type decl) | useful empty statement (empty statement) + public final static int Bit2 = 0x2; // return type (operator) | name reference kind (name ref) | has local type (type, method, field decl) + public final static int Bit3 = 0x4; // return type (operator) | name reference kind (name ref) | implicit this (this ref) + public final static int Bit4 = 0x8; // return type (operator) | first assignment to local (local decl) | undocumented empty block (block, type and method decl) + public final static int Bit5 = 0x10; // value for return (expression) | has all method bodies (unit) + public final static int Bit6 = 0x20; // depth (name ref, msg) | only value required (binary expression) | ignore need cast check (cast expression) + public final static int Bit7 = 0x40; // depth (name ref, msg) | operator (operator) | need runtime checkcast (cast expression) + public final static int Bit8 = 0x80; // depth (name ref, msg) | operator (operator) + public final static int Bit9 = 0x100; // depth (name ref, msg) | operator (operator) | is local type (type decl) + public final static int Bit10= 0x200; // depth (name ref, msg) | operator (operator) | is anonymous type (type decl) + public final static int Bit11 = 0x400; // depth (name ref, msg) | operator (operator) | is member type (type decl) + public final static int Bit12 = 0x800; // depth (name ref, msg) | operator (operator) + public final static int Bit13 = 0x1000; // depth (name ref, msg) + public final static int Bit14 = 0x2000; // strictly assigned (reference lhs) + public final static int Bit15 = 0x4000; // is unnecessary cast (expression) + public final static int Bit16 = 0x8000; // in javadoc comment (name ref, type ref, msg) + public final static int Bit17 = 0x10000; // compound assigned (reference lhs) + public final static int Bit18 = 0x20000; + public final static int Bit19 = 0x40000; + public final static int Bit20 = 0x80000; + public final static int Bit21 = 0x100000; + public final static int Bit22 = 0x200000; // parenthesis count (expression) + public final static int Bit23 = 0x400000; // parenthesis count (expression) + public final static int Bit24 = 0x800000; // parenthesis count (expression) + public final static int Bit25 = 0x1000000; // parenthesis count (expression) + public final static int Bit26 = 0x2000000; // parenthesis count (expression) + public final static int Bit27 = 0x4000000; // parenthesis count (expression) + public final static int Bit28 = 0x8000000; // parenthesis count (expression) + public final static int Bit29 = 0x10000000; // parenthesis count (expression) + public final static int Bit30 = 0x20000000; // assignment with no effect (assignment) | elseif (if statement) + public final static int Bit31 = 0x40000000; // local declaration reachable (local decl) + public final static int Bit32 = 0x80000000; // reachable (statement) + + public final static long Bit32L = 0x80000000L; + public final static long Bit33L = 0x100000000L; + public final static long Bit34L = 0x200000000L; + public final static long Bit35L = 0x400000000L; + public final static long Bit36L = 0x800000000L; + public final static long Bit37L = 0x1000000000L; + public final static long Bit38L = 0x2000000000L; + public final static long Bit39L = 0x4000000000L; + public final static long Bit40L = 0x8000000000L; + + public int bits = IsReachableMASK; // reachable by default + + // for operators + public static final int ReturnTypeIDMASK = Bit1|Bit2|Bit3|Bit4; + public static final int OperatorSHIFT = 6; // Bit7 -> Bit12 + public static final int OperatorMASK = Bit7|Bit8|Bit9|Bit10|Bit11|Bit12; // 6 bits for operator ID + + // for binary expressions + public static final int ValueForReturnMASK = Bit5; + public static final int OnlyValueRequiredMASK = Bit6; + + // for cast expressions + public static final int UnnecessaryCastMask = Bit15; + public static final int NeedRuntimeCheckCastMASK = Bit7; + public static final int IgnoreNeedForCastCheckMASK = Bit6; + + // for name references + public static final int RestrictiveFlagMASK = Bit1|Bit2|Bit3; + public static final int FirstAssignmentToLocalMASK = Bit4; + + // for this reference + public static final int IsImplicitThisMask = Bit3; + + // for single name references + public static final int DepthSHIFT = 5; // Bit6 -> Bit13 + public static final int DepthMASK = Bit6|Bit7|Bit8|Bit9|Bit10|Bit11|Bit12|Bit13; // 8 bits for actual depth value (max. 255) + + // for statements + public static final int IsReachableMASK = Bit32; + public static final int IsLocalDeclarationReachableMASK = Bit31; + + // for type declaration + public static final int AddAssertionMASK = Bit1; + public static final int IsLocalTypeMASK = Bit9; + public static final int IsAnonymousTypeMASK = Bit10; // used to test for anonymous + public static final int AnonymousAndLocalMask = IsAnonymousTypeMASK | IsLocalTypeMASK; // used to set anonymous marker + public static final int IsMemberTypeMASK = Bit11; // local member do not know it is local at parse time (need to look at binding) + + // for type, method and field declarations + public static final int HasLocalTypeMASK = Bit2; // cannot conflict with AddAssertionMASK + + // for expression + public static final int ParenthesizedSHIFT = 21; // Bit22 -> Bit29 + public static final int ParenthesizedMASK = Bit22|Bit23|Bit24|Bit25|Bit26|Bit27|Bit28|Bit29; // 8 bits for parenthesis count value (max. 255) + + // for assignment + public static final int IsAssignmentWithNoEffectMASK = Bit30; + + // for references on lhs of assignment + public static final int IsStrictlyAssignedMASK = Bit14; // set only for true assignments, as opposed to compound ones + public static final int IsCompoundAssignedMASK = Bit17; // set only for compound assignments, as opposed to other ones + + // for empty statement + public static final int IsUsefulEmptyStatementMASK = Bit1; + + // for block and method declaration + public static final int UndocumentedEmptyBlockMASK = Bit4; + + // for compilation unit + public static final int HasAllMethodBodies = Bit5; + + // for references in Javadoc comments + public static final int InsideJavadoc = Bit16; + + // for if statement + public static final int IsElseIfStatement = Bit30; + + public ASTNode() { + + super(); + } + + public ASTNode concreteStatement() { + return this; + } + + /* Answer true if the field use is considered deprecated. + * An access in the same compilation unit is allowed. + */ + public final boolean isFieldUseDeprecated(FieldBinding field, Scope scope, boolean isStrictlyAssigned) { + + if (!isStrictlyAssigned && field.isPrivate() && !scope.isDefinedInField(field)) { + // ignore cases where field is used from within inside itself + field.modifiers |= AccPrivateUsed; + } + + if (!field.isViewedAsDeprecated()) return false; + + // inside same unit - no report + if (scope.isDefinedInSameUnit(field.declaringClass)) return false; + + // if context is deprecated, may avoid reporting + if (!scope.environment().options.reportDeprecationInsideDeprecatedCode && scope.isInsideDeprecatedCode()) return false; + return true; + } + + public boolean isImplicitThis() { + + return false; + } + + /* Answer true if the method use is considered deprecated. + * An access in the same compilation unit is allowed. + */ + public final boolean isMethodUseDeprecated(MethodBinding method, Scope scope) { + + if (method.isPrivate() && !scope.isDefinedInMethod(method)) { + // ignore cases where method is used from within inside itself (e.g. direct recursions) + method.modifiers |= AccPrivateUsed; + } + + if (!method.isViewedAsDeprecated()) return false; + + // inside same unit - no report + if (scope.isDefinedInSameUnit(method.declaringClass)) return false; + + // if context is deprecated, may avoid reporting + if (!scope.environment().options.reportDeprecationInsideDeprecatedCode && scope.isInsideDeprecatedCode()) return false; + return true; + } + + public boolean isSuper() { + + return false; + } + + public boolean isThis() { + + return false; + } + + /* Answer true if the type use is considered deprecated. + * An access in the same compilation unit is allowed. + */ + public final boolean isTypeUseDeprecated(TypeBinding type, Scope scope) { + + if (type.isArrayType()) + type = ((ArrayBinding) type).leafComponentType; + if (type.isBaseType()) + return false; + + ReferenceBinding refType = (ReferenceBinding) type; + + if (refType.isPrivate() && !scope.isDefinedInType(refType)) { + // ignore cases where type is used from within inside itself + refType.modifiers |= AccPrivateUsed; + } + + if (!refType.isViewedAsDeprecated()) return false; + + // inside same unit - no report + if (scope.isDefinedInSameUnit(refType)) return false; + + // if context is deprecated, may avoid reporting + if (!scope.environment().options.reportDeprecationInsideDeprecatedCode && scope.isInsideDeprecatedCode()) return false; + return true; + } + + public abstract StringBuffer print(int indent, StringBuffer output); + + public static StringBuffer printIndent(int indent, StringBuffer output) { + + for (int i = indent; i > 0; i--) output.append(" "); //$NON-NLS-1$ + return output; + } + + public static StringBuffer printModifiers(int modifiers, StringBuffer output) { + + if ((modifiers & AccPublic) != 0) + output.append("public "); //$NON-NLS-1$ + if ((modifiers & AccPrivate) != 0) + output.append("private "); //$NON-NLS-1$ + if ((modifiers & AccProtected) != 0) + output.append("protected "); //$NON-NLS-1$ + if ((modifiers & AccStatic) != 0) + output.append("static "); //$NON-NLS-1$ + if ((modifiers & AccFinal) != 0) + output.append("final "); //$NON-NLS-1$ + if ((modifiers & AccSynchronized) != 0) + output.append("synchronized "); //$NON-NLS-1$ + if ((modifiers & AccVolatile) != 0) + output.append("volatile "); //$NON-NLS-1$ + if ((modifiers & AccTransient) != 0) + output.append("transient "); //$NON-NLS-1$ + if ((modifiers & AccNative) != 0) + output.append("native "); //$NON-NLS-1$ + if ((modifiers & AccAbstract) != 0) + output.append("abstract "); //$NON-NLS-1$ + return output; + } + public int sourceStart() { + return this.sourceStart; + } + public int sourceEnd() { + return this.sourceEnd; + } + public String toString() { + + return print(0, new StringBuffer(30)).toString(); + } + + public void traverse(ASTVisitor visitor, BlockScope scope) { + // do nothing by default + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java b/src/java/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java new file mode 100644 index 0000000..c25253e --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java @@ -0,0 +1,398 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.core.compiler.*; +import org.eclipse.jdt.internal.compiler.*; +import org.eclipse.jdt.internal.compiler.flow.FlowInfo; +import org.eclipse.jdt.internal.compiler.flow.InitializationFlowContext; +import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.lookup.*; +import org.eclipse.jdt.internal.compiler.problem.*; +import org.eclipse.jdt.internal.compiler.parser.*; + +public abstract class AbstractMethodDeclaration + extends ASTNode + implements ProblemSeverities, ReferenceContext { + + public MethodScope scope; + //it is not relevent for constructor but it helps to have the name of the constructor here + //which is always the name of the class.....parsing do extra work to fill it up while it do not have to.... + public char[] selector; + public int declarationSourceStart; + public int declarationSourceEnd; + public int modifiers; + public int modifiersSourceStart; + public Argument[] arguments; + public TypeReference[] thrownExceptions; + public Statement[] statements; + public int explicitDeclarations; + public MethodBinding binding; + public boolean ignoreFurtherInvestigation = false; + public boolean needFreeReturn = false; + + public Javadoc javadoc; + + public int bodyStart; + public int bodyEnd = -1; + public CompilationResult compilationResult; + + public boolean errorInSignature = false; + + AbstractMethodDeclaration(CompilationResult compilationResult){ + this.compilationResult = compilationResult; + } + + /* + * We cause the compilation task to abort to a given extent. + */ + public void abort(int abortLevel, IProblem problem) { + + switch (abortLevel) { + case AbortCompilation : + throw new AbortCompilation(this.compilationResult, problem); + case AbortCompilationUnit : + throw new AbortCompilationUnit(this.compilationResult, problem); + case AbortType : + throw new AbortType(this.compilationResult, problem); + default : + throw new AbortMethod(this.compilationResult, problem); + } + } + + public abstract void analyseCode(ClassScope classScope, InitializationFlowContext initializationContext, FlowInfo info); + + /** + * Bind and add argument's binding into the scope of the method + */ + public void bindArguments() { + + if (this.arguments != null) { + // by default arguments in abstract/native methods are considered to be used (no complaint is expected) + boolean used = this.binding == null || this.binding.isAbstract() || this.binding.isNative(); + + int length = this.arguments.length; + for (int i = 0; i < length; i++) { + TypeBinding argType = this.binding == null ? null : this.binding.parameters[i]; + this.arguments[i].bind(this.scope, argType, used); + } + } + } + + /** + * Record the thrown exception type bindings in the corresponding type references. + */ + public void bindThrownExceptions() { + + if (this.thrownExceptions != null + && this.binding != null + && this.binding.thrownExceptions != null) { + int thrownExceptionLength = this.thrownExceptions.length; + int length = this.binding.thrownExceptions.length; + if (length == thrownExceptionLength) { + for (int i = 0; i < length; i++) { + this.thrownExceptions[i].resolvedType = this.binding.thrownExceptions[i]; + } + } else { + int bindingIndex = 0; + for (int i = 0; i < thrownExceptionLength && bindingIndex < length; i++) { + TypeReference thrownException = this.thrownExceptions[i]; + ReferenceBinding thrownExceptionBinding = this.binding.thrownExceptions[bindingIndex]; + char[][] bindingCompoundName = thrownExceptionBinding.compoundName; + if (thrownException instanceof SingleTypeReference) { + // single type reference + int lengthName = bindingCompoundName.length; + char[] thrownExceptionTypeName = thrownException.getTypeName()[0]; + if (CharOperation.equals(thrownExceptionTypeName, bindingCompoundName[lengthName - 1])) { + thrownException.resolvedType = thrownExceptionBinding; + bindingIndex++; + } + } else { + // qualified type reference + if (CharOperation.equals(thrownException.getTypeName(), bindingCompoundName)) { + thrownException.resolvedType = thrownExceptionBinding; + bindingIndex++; + } + } + } + } + } + } + + public CompilationResult compilationResult() { + + return this.compilationResult; + } + + /** + * Bytecode generation for a method + * @param classScope + * @param classFile + */ + public void generateCode(ClassScope classScope, ClassFile classFile) { + + int problemResetPC = 0; + classFile.codeStream.wideMode = false; // reset wideMode to false + if (this.ignoreFurtherInvestigation) { + // method is known to have errors, dump a problem method + if (this.binding == null) + return; // handle methods with invalid signature or duplicates + int problemsLength; + IProblem[] problems = + this.scope.referenceCompilationUnit().compilationResult.getProblems(); + IProblem[] problemsCopy = new IProblem[problemsLength = problems.length]; + System.arraycopy(problems, 0, problemsCopy, 0, problemsLength); + classFile.addProblemMethod(this, this.binding, problemsCopy); + return; + } + // regular code generation + try { + problemResetPC = classFile.contentsOffset; + this.generateCode(classFile); + } catch (AbortMethod e) { + // a fatal error was detected during code generation, need to restart code gen if possible + if (e.compilationResult == CodeStream.RESTART_IN_WIDE_MODE) { + // a branch target required a goto_w, restart code gen in wide mode. + try { + classFile.contentsOffset = problemResetPC; + classFile.methodCount--; + classFile.codeStream.wideMode = true; // request wide mode + this.generateCode(classFile); // restart method generation + } catch (AbortMethod e2) { + int problemsLength; + IProblem[] problems = + this.scope.referenceCompilationUnit().compilationResult.getAllProblems(); + IProblem[] problemsCopy = new IProblem[problemsLength = problems.length]; + System.arraycopy(problems, 0, problemsCopy, 0, problemsLength); + classFile.addProblemMethod(this, this.binding, problemsCopy, problemResetPC); + } + } else { + // produce a problem method accounting for this fatal error + int problemsLength; + IProblem[] problems = + this.scope.referenceCompilationUnit().compilationResult.getAllProblems(); + IProblem[] problemsCopy = new IProblem[problemsLength = problems.length]; + System.arraycopy(problems, 0, problemsCopy, 0, problemsLength); + classFile.addProblemMethod(this, this.binding, problemsCopy, problemResetPC); + } + } + } + + private void generateCode(ClassFile classFile) { + + classFile.generateMethodInfoHeader(this.binding); + int methodAttributeOffset = classFile.contentsOffset; + int attributeNumber = classFile.generateMethodInfoAttribute(this.binding); + if ((!this.binding.isNative()) && (!this.binding.isAbstract())) { + int codeAttributeOffset = classFile.contentsOffset; + classFile.generateCodeAttributeHeader(); + CodeStream codeStream = classFile.codeStream; + codeStream.reset(this, classFile); + // initialize local positions + this.scope.computeLocalVariablePositions(this.binding.isStatic() ? 0 : 1, codeStream); + + // arguments initialization for local variable debug attributes + if (this.arguments != null) { + for (int i = 0, max = this.arguments.length; i < max; i++) { + LocalVariableBinding argBinding; + codeStream.addVisibleLocalVariable(argBinding = this.arguments[i].binding); + argBinding.recordInitializationStartPC(0); + } + } + if (this.statements != null) { + for (int i = 0, max = this.statements.length; i < max; i++) + this.statements[i].generateCode(this.scope, codeStream); + } + if (this.needFreeReturn) { + codeStream.return_(); + } + // local variable attributes + codeStream.exitUserScope(this.scope); + codeStream.recordPositionsFrom(0, this.declarationSourceEnd); + classFile.completeCodeAttribute(codeAttributeOffset); + attributeNumber++; + } else { + checkArgumentsSize(); + } + classFile.completeMethodInfo(methodAttributeOffset, attributeNumber); + + // if a problem got reported during code gen, then trigger problem method creation + if (this.ignoreFurtherInvestigation) { + throw new AbortMethod(this.scope.referenceCompilationUnit().compilationResult, null); + } + } + + private void checkArgumentsSize() { + TypeBinding[] parameters = this.binding.parameters; + int size = 1; // an abstact method or a native method cannot be static + for (int i = 0, max = parameters.length; i < max; i++) { + TypeBinding parameter = parameters[i]; + if (parameter == LongBinding || parameter == DoubleBinding) { + size += 2; + } else { + size++; + } + if (size > 0xFF) { + this.scope.problemReporter().noMoreAvailableSpaceForArgument(this.scope.locals[i], this.scope.locals[i].declaration); + } + } + } + + public boolean hasErrors() { + return this.ignoreFurtherInvestigation; + } + + public boolean isAbstract() { + + if (this.binding != null) + return this.binding.isAbstract(); + return (this.modifiers & AccAbstract) != 0; + } + + public boolean isClinit() { + + return false; + } + + public boolean isConstructor() { + + return false; + } + + public boolean isDefaultConstructor() { + + return false; + } + + public boolean isInitializationMethod() { + + return false; + } + + public boolean isNative() { + + if (this.binding != null) + return this.binding.isNative(); + return (this.modifiers & AccNative) != 0; + } + + public boolean isStatic() { + + if (this.binding != null) + return this.binding.isStatic(); + return (this.modifiers & AccStatic) != 0; + } + + /** + * Fill up the method body with statement + * @param parser + * @param unit + */ + public abstract void parseStatements( + Parser parser, + CompilationUnitDeclaration unit); + + public StringBuffer print(int tab, StringBuffer output) { + + printIndent(tab, output); + printModifiers(this.modifiers, output); + printReturnType(0, output).append(this.selector).append('('); + if (this.arguments != null) { + for (int i = 0; i < this.arguments.length; i++) { + if (i > 0) output.append(", "); //$NON-NLS-1$ + this.arguments[i].print(0, output); + } + } + output.append(')'); + if (this.thrownExceptions != null) { + output.append(" throws "); //$NON-NLS-1$ + for (int i = 0; i < this.thrownExceptions.length; i++) { + if (i > 0) output.append(", "); //$NON-NLS-1$ + this.thrownExceptions[i].print(0, output); + } + } + printBody(tab + 1, output); + return output; + } + + public StringBuffer printBody(int indent, StringBuffer output) { + + if (isAbstract() || (this.modifiers & AccSemicolonBody) != 0) + return output.append(';'); + + output.append(" {"); //$NON-NLS-1$ + if (this.statements != null) { + for (int i = 0; i < this.statements.length; i++) { + output.append('\n'); + this.statements[i].printStatement(indent, output); + } + } + output.append('\n'); //$NON-NLS-1$ + printIndent(indent == 0 ? 0 : indent - 1, output).append('}'); + return output; + } + + public StringBuffer printReturnType(int indent, StringBuffer output) { + + return output; + } + + public void resolve(ClassScope upperScope) { + + if (this.binding == null) { + this.ignoreFurtherInvestigation = true; + } + + try { + bindArguments(); + bindThrownExceptions(); + resolveJavadoc(); + resolveStatements(); + } catch (AbortMethod e) { // ========= abort on fatal error ============= + this.ignoreFurtherInvestigation = true; + } + } + + public void resolveJavadoc() { + + if (this.binding == null) return; + if (this.javadoc != null) { + this.javadoc.resolve(this.scope); + return; + } + if (this.binding.declaringClass != null && !this.binding.declaringClass.isLocalType()) { + this.scope.problemReporter().javadocMissing(this.sourceStart, this.sourceEnd, this.binding.modifiers); + } + } + + public void resolveStatements() { + + if (this.statements != null) { + for (int i = 0, length = this.statements.length; i < length; i++) { + this.statements[i].resolve(this.scope); + } + } else if ((this.bits & UndocumentedEmptyBlockMASK) != 0) { + this.scope.problemReporter().undocumentedEmptyBlock(this.bodyStart-1, this.bodyEnd+1); + } + } + + public void tagAsHavingErrors() { + + this.ignoreFurtherInvestigation = true; + } + + public void traverse( + ASTVisitor visitor, + ClassScope classScope) { + // default implementation: subclass will define it + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/AbstractVariableDeclaration.java b/src/java/org/eclipse/jdt/internal/compiler/ast/AbstractVariableDeclaration.java new file mode 100644 index 0000000..cce62fc --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/AbstractVariableDeclaration.java @@ -0,0 +1,87 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.flow.FlowContext; +import org.eclipse.jdt.internal.compiler.flow.FlowInfo; +import org.eclipse.jdt.internal.compiler.lookup.BlockScope; +import org.eclipse.jdt.internal.compiler.lookup.InvocationSite; +import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; + +public abstract class AbstractVariableDeclaration extends Statement implements InvocationSite { + public int declarationEnd; + public int declarationSourceEnd; + public int declarationSourceStart; + public int hiddenVariableDepth; // used to diagnose hiding scenarii + public Expression initialization; + public int modifiers; + public int modifiersSourceStart; + + public char[] name; + + public TypeReference type; + + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + return flowInfo; + } + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#isSuperAccess() + */ + public boolean isSuperAccess() { + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#isTypeAccess() + */ + public boolean isTypeAccess() { + return false; + } + + + public StringBuffer printStatement(int indent, StringBuffer output) { + + printIndent(indent, output); + printModifiers(this.modifiers, output); + type.print(0, output).append(' ').append(this.name); + if (initialization != null) { + output.append(" = "); //$NON-NLS-1$ + initialization.printExpression(indent, output); + } + return output.append(';'); + } + + public void resolve(BlockScope scope) { + // do nothing by default (redefined for local variables) + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#setActualReceiverType(org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding) + */ + public void setActualReceiverType(ReferenceBinding receiverType) { + // do nothing by default + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#setDepth(int) + */ + public void setDepth(int depth) { + + this.hiddenVariableDepth = depth; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#setFieldIndex(int) + */ + public void setFieldIndex(int depth) { + // do nothing by default + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java b/src/java/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java new file mode 100644 index 0000000..2a47d4d --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java @@ -0,0 +1,290 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class AllocationExpression + extends Expression + implements InvocationSite { + + public TypeReference type; + public Expression[] arguments; + public MethodBinding binding; + + MethodBinding syntheticAccessor; + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + // check captured variables are initialized in current context (26134) + checkCapturedLocalInitializationIfNecessary(this.binding.declaringClass, currentScope, flowInfo); + + // process arguments + if (arguments != null) { + for (int i = 0, count = arguments.length; i < count; i++) { + flowInfo = + arguments[i] + .analyseCode(currentScope, flowContext, flowInfo) + .unconditionalInits(); + } + } + // record some dependency information for exception types + ReferenceBinding[] thrownExceptions; + if (((thrownExceptions = this.binding.thrownExceptions).length) != 0) { + // check exception handling + flowContext.checkExceptionHandlers( + thrownExceptions, + this, + flowInfo, + currentScope); + } + manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo); + manageSyntheticAccessIfNecessary(currentScope, flowInfo); + + return flowInfo; + } + + public void checkCapturedLocalInitializationIfNecessary(ReferenceBinding checkedType, BlockScope currentScope, FlowInfo flowInfo) { + + if (checkedType.isLocalType() + && !checkedType.isAnonymousType() + && !currentScope.isDefinedInType(checkedType)) { // only check external allocations + NestedTypeBinding nestedType = (NestedTypeBinding) checkedType; + SyntheticArgumentBinding[] syntheticArguments = nestedType.syntheticOuterLocalVariables(); + if (syntheticArguments != null) + for (int i = 0, count = syntheticArguments.length; i < count; i++){ + SyntheticArgumentBinding syntheticArgument = syntheticArguments[i]; + LocalVariableBinding targetLocal; + if ((targetLocal = syntheticArgument.actualOuterLocalVariable) == null) continue; + if (targetLocal.declaration != null && !flowInfo.isDefinitelyAssigned(targetLocal)){ + currentScope.problemReporter().uninitializedLocalVariable(targetLocal, this); + } + } + + } + } + + public Expression enclosingInstance() { + return null; + } + + public void generateCode( + BlockScope currentScope, + CodeStream codeStream, + boolean valueRequired) { + + int pc = codeStream.position; + ReferenceBinding allocatedType = binding.declaringClass; + + codeStream.new_(allocatedType); + if (valueRequired) { + codeStream.dup(); + } + // better highlight for allocation: display the type individually + codeStream.recordPositionsFrom(pc, type.sourceStart); + + // handling innerclass instance allocation - enclosing instance arguments + if (allocatedType.isNestedType()) { + codeStream.generateSyntheticEnclosingInstanceValues( + currentScope, + allocatedType, + enclosingInstance(), + this); + } + // generate the arguments for constructor + if (arguments != null) { + for (int i = 0, count = arguments.length; i < count; i++) { + arguments[i].generateCode(currentScope, codeStream, true); + } + } + // handling innerclass instance allocation - outer local arguments + if (allocatedType.isNestedType()) { + codeStream.generateSyntheticOuterArgumentValues( + currentScope, + allocatedType, + this); + } + // invoke constructor + if (syntheticAccessor == null) { + codeStream.invokespecial(binding); + } else { + // synthetic accessor got some extra arguments appended to its signature, which need values + for (int i = 0, + max = syntheticAccessor.parameters.length - binding.parameters.length; + i < max; + i++) { + codeStream.aconst_null(); + } + codeStream.invokespecial(syntheticAccessor); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public boolean isSuperAccess() { + + return false; + } + + public boolean isTypeAccess() { + + return true; + } + + /* Inner emulation consists in either recording a dependency + * link only, or performing one level of propagation. + * + * Dependency mechanism is used whenever dealing with source target + * types, since by the time we reach them, we might not yet know their + * exact need. + */ + public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) { + + if (!flowInfo.isReachable()) return; + ReferenceBinding allocatedType; + + // perform some emulation work in case there is some and we are inside a local type only + if ((allocatedType = binding.declaringClass).isNestedType() + && currentScope.enclosingSourceType().isLocalType()) { + + if (allocatedType.isLocalType()) { + ((LocalTypeBinding) allocatedType).addInnerEmulationDependent(currentScope, false); + // request cascade of accesses + } else { + // locally propagate, since we already now the desired shape for sure + currentScope.propagateInnerEmulation(allocatedType, false); + // request cascade of accesses + } + } + } + + public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) { + + if (!flowInfo.isReachable()) return; + if (binding.isPrivate() + && (currentScope.enclosingSourceType() != binding.declaringClass)) { + + if (currentScope + .environment() + .options + .isPrivateConstructorAccessChangingVisibility) { + binding.tagForClearingPrivateModifier(); + // constructor will not be dumped as private, no emulation required thus + } else { + syntheticAccessor = + ((SourceTypeBinding) binding.declaringClass).addSyntheticMethod(binding, isSuperAccess()); + currentScope.problemReporter().needToEmulateMethodAccess(binding, this); + } + } + } + + public StringBuffer printExpression(int indent, StringBuffer output) { + + output.append("new "); //$NON-NLS-1$ + type.printExpression(0, output); + output.append('('); + if (arguments != null) { + for (int i = 0; i < arguments.length; i++) { + if (i > 0) output.append(", "); //$NON-NLS-1$ + arguments[i].printExpression(0, output); + } + } + return output.append(')'); + } + + public TypeBinding resolveType(BlockScope scope) { + + // Propagate the type checking to the arguments, and check if the constructor is defined. + constant = NotAConstant; + this.resolvedType = type.resolveType(scope); + // will check for null after args are resolved + + // buffering the arguments' types + boolean argsContainCast = false; + TypeBinding[] argumentTypes = NoParameters; + if (arguments != null) { + boolean argHasError = false; + int length = arguments.length; + argumentTypes = new TypeBinding[length]; + for (int i = 0; i < length; i++) { + Expression argument = this.arguments[i]; + if (argument instanceof CastExpression) { + argument.bits |= IgnoreNeedForCastCheckMASK; // will check later on + argsContainCast = true; + } + if ((argumentTypes[i] = argument.resolveType(scope)) == null) { + argHasError = true; + } + } + if (argHasError) { + return this.resolvedType; + } + } + if (this.resolvedType == null) + return null; + + if (!this.resolvedType.canBeInstantiated()) { + scope.problemReporter().cannotInstantiate(type, this.resolvedType); + return this.resolvedType; + } + ReferenceBinding allocationType = (ReferenceBinding) this.resolvedType; + if (!(binding = scope.getConstructor(allocationType, argumentTypes, this)) + .isValidBinding()) { + if (binding.declaringClass == null) + binding.declaringClass = allocationType; + scope.problemReporter().invalidConstructor(this, binding); + return this.resolvedType; + } + if (isMethodUseDeprecated(binding, scope)) + scope.problemReporter().deprecatedMethod(binding, this); + + if (arguments != null) { + for (int i = 0; i < arguments.length; i++) { + arguments[i].implicitWidening(binding.parameters[i], argumentTypes[i]); + } + if (argsContainCast) { + CastExpression.checkNeedForArgumentCasts(scope, null, allocationType, binding, this.arguments, argumentTypes, this); + } + } + return allocationType; + } + + public void setActualReceiverType(ReferenceBinding receiverType) { + // ignored + } + + public void setDepth(int i) { + // ignored + } + + public void setFieldIndex(int i) { + // ignored + } + + public void traverse(ASTVisitor visitor, BlockScope scope) { + + if (visitor.visit(this, scope)) { + int argumentsLength; + type.traverse(visitor, scope); + if (arguments != null) { + argumentsLength = arguments.length; + for (int i = 0; i < argumentsLength; i++) + arguments[i].traverse(visitor, scope); + } + } + visitor.endVisit(this, scope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/Argument.java b/src/java/org/eclipse/jdt/internal/compiler/ast/Argument.java new file mode 100644 index 0000000..b6669ac --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/Argument.java @@ -0,0 +1,120 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class Argument extends LocalDeclaration { + + // prefix for setter method (to recognize special hiding argument) + private final static char[] SET = "set".toCharArray(); //$NON-NLS-1$ + + public Argument(char[] name, long posNom, TypeReference tr, int modifiers) { + + super(name, (int) (posNom >>> 32), (int) posNom); + this.declarationSourceEnd = (int) posNom; + this.modifiers = modifiers; + type = tr; + this.bits |= IsLocalDeclarationReachableMASK; + } + + public void bind(MethodScope scope, TypeBinding typeBinding, boolean used) { + + if (this.type != null) + this.type.resolvedType = typeBinding; + // record the resolved type into the type reference + int modifierFlag = this.modifiers; + + Binding existingVariable = scope.getBinding(name, BindingIds.VARIABLE, this, false /*do not resolve hidden field*/); + if (existingVariable != null && existingVariable.isValidBinding()){ + if (existingVariable instanceof LocalVariableBinding && this.hiddenVariableDepth == 0) { + scope.problemReporter().redefineArgument(this); + return; + } + boolean isSpecialArgument = false; + if (existingVariable instanceof FieldBinding) { + if (scope.isInsideConstructor()) { + isSpecialArgument = true; // constructor argument + } else { + AbstractMethodDeclaration methodDecl = scope.referenceMethod(); + if (methodDecl != null && CharOperation.prefixEquals(SET, methodDecl.selector)) { + isSpecialArgument = true; // setter argument + } + } + } + scope.problemReporter().localVariableHiding(this, existingVariable, isSpecialArgument); + } + + scope.addLocalVariable( + this.binding = + new LocalVariableBinding(this, typeBinding, modifierFlag, true)); + //true stand for argument instead of just local + if (typeBinding != null && isTypeUseDeprecated(typeBinding, scope)) + scope.problemReporter().deprecatedType(typeBinding, this.type); + this.binding.declaration = this; + this.binding.useFlag = used ? LocalVariableBinding.USED : LocalVariableBinding.UNUSED; + } + + public StringBuffer print(int indent, StringBuffer output) { + + printIndent(indent, output); + printModifiers(this.modifiers, output); + if (type == null) { + output.append(" "); //$NON-NLS-1$ + } else { + type.print(0, output).append(' '); + } + return output.append(this.name); + } + + public StringBuffer printStatement(int indent, StringBuffer output) { + + return print(indent, output).append(';'); + } + + public TypeBinding resolveForCatch(BlockScope scope) { + + // resolution on an argument of a catch clause + // provide the scope with a side effect : insertion of a LOCAL + // that represents the argument. The type must be from JavaThrowable + + TypeBinding tb = type.resolveTypeExpecting(scope, scope.getJavaLangThrowable()); + if (tb == null) + return null; + + Binding existingVariable = scope.getBinding(name, BindingIds.VARIABLE, this, false /*do not resolve hidden field*/); + if (existingVariable != null && existingVariable.isValidBinding()){ + if (existingVariable instanceof LocalVariableBinding && this.hiddenVariableDepth == 0) { + scope.problemReporter().redefineArgument(this); + return null; + } + scope.problemReporter().localVariableHiding(this, existingVariable, false); + } + + binding = new LocalVariableBinding(this, tb, modifiers, false); // argument decl, but local var (where isArgument = false) + scope.addLocalVariable(binding); + binding.constant = NotAConstant; + return tb; + } + + public void traverse(ASTVisitor visitor, BlockScope scope) { + + if (visitor.visit(this, scope)) { + if (type != null) + type.traverse(visitor, scope); + if (initialization != null) + initialization.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/ArrayAllocationExpression.java b/src/java/org/eclipse/jdt/internal/compiler/ast/ArrayAllocationExpression.java new file mode 100644 index 0000000..d9ab28d --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/ArrayAllocationExpression.java @@ -0,0 +1,187 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class ArrayAllocationExpression extends Expression { + + public TypeReference type; + + //dimensions.length gives the number of dimensions, but the + // last ones may be nulled as in new int[4][5][][] + public Expression[] dimensions; + public ArrayInitializer initializer; + + /** + * ArrayAllocationExpression constructor comment. + */ + public ArrayAllocationExpression() { + super(); + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + for (int i = 0, max = dimensions.length; i < max; i++) { + Expression dim; + if ((dim = dimensions[i]) != null) { + flowInfo = dim.analyseCode(currentScope, flowContext, flowInfo); + } + } + if (initializer != null) { + return initializer.analyseCode(currentScope, flowContext, flowInfo); + } + return flowInfo; + } + + /** + * Code generation for a array allocation expression + */ + public void generateCode( + BlockScope currentScope, + CodeStream codeStream, + boolean valueRequired) { + + int pc = codeStream.position; + + if (initializer != null) { + initializer.generateCode(currentScope, codeStream, valueRequired); + return; + } + + int nonNullDimensionsLength = 0; + for (int i = 0, max = dimensions.length; i < max; i++) + if (dimensions[i] != null) { + dimensions[i].generateCode(currentScope, codeStream, true); + nonNullDimensionsLength++; + } + + // Generate a sequence of bytecodes corresponding to an array allocation + if (this.resolvedType.dimensions() == 1) { + // Mono-dimensional array + codeStream.newArray(currentScope, (ArrayBinding)this.resolvedType); + } else { + // Multi-dimensional array + codeStream.multianewarray(this.resolvedType, nonNullDimensionsLength); + } + + if (valueRequired) { + codeStream.generateImplicitConversion(implicitConversion); + } else { + codeStream.pop(); + } + + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + + public StringBuffer printExpression(int indent, StringBuffer output) { + + output.append("new "); //$NON-NLS-1$ + type.print(0, output); + for (int i = 0; i < dimensions.length; i++) { + if (dimensions[i] == null) + output.append("[]"); //$NON-NLS-1$ + else { + output.append('['); + dimensions[i].printExpression(0, output); + output.append(']'); + } + } + if (initializer != null) initializer.printExpression(0, output); + return output; + } + + public TypeBinding resolveType(BlockScope scope) { + + // Build an array type reference using the current dimensions + // The parser does not check for the fact that dimension may be null + // only at the -end- like new int [4][][]. The parser allows new int[][4][] + // so this must be checked here......(this comes from a reduction to LL1 grammar) + + TypeBinding referenceType = type.resolveType(scope); + + // will check for null after dimensions are checked + constant = Constant.NotAConstant; + if (referenceType == VoidBinding) { + scope.problemReporter().cannotAllocateVoidArray(this); + referenceType = null; + } + + // check the validity of the dimension syntax (and test for all null dimensions) + int explicitDimIndex = -1; + for (int i = dimensions.length; --i >= 0;) { + if (dimensions[i] != null) { + if (explicitDimIndex < 0) explicitDimIndex = i; + } else if (explicitDimIndex> 0) { + // should not have an empty dimension before an non-empty one + scope.problemReporter().incorrectLocationForEmptyDimension(this, i); + } + } + + // explicitDimIndex < 0 says if all dimensions are nulled + // when an initializer is given, no dimension must be specified + if (initializer == null) { + if (explicitDimIndex < 0) { + scope.problemReporter().mustDefineDimensionsOrInitializer(this); + } + } else if (explicitDimIndex >= 0) { + scope.problemReporter().cannotDefineDimensionsAndInitializer(this); + } + + // dimensions resolution + for (int i = 0; i <= explicitDimIndex; i++) { + if (dimensions[i] != null) { + TypeBinding dimensionType = dimensions[i].resolveTypeExpecting(scope, IntBinding); + if (dimensionType != null) { + dimensions[i].implicitWidening(IntBinding, dimensionType); + } + } + } + + // building the array binding + if (referenceType != null) { + if (dimensions.length > 255) { + scope.problemReporter().tooManyDimensions(this); + } + this.resolvedType = scope.createArray(referenceType, dimensions.length); + + // check the initializer + if (initializer != null) { + if ((initializer.resolveTypeExpecting(scope, this.resolvedType)) != null) + initializer.binding = (ArrayBinding)this.resolvedType; + } + } + return this.resolvedType; + } + + + public void traverse(ASTVisitor visitor, BlockScope scope) { + + if (visitor.visit(this, scope)) { + int dimensionsLength = dimensions.length; + type.traverse(visitor, scope); + for (int i = 0; i < dimensionsLength; i++) { + if (dimensions[i] != null) + dimensions[i].traverse(visitor, scope); + } + if (initializer != null) + initializer.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/ArrayInitializer.java b/src/java/org/eclipse/jdt/internal/compiler/ast/ArrayInitializer.java new file mode 100644 index 0000000..b717047 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/ArrayInitializer.java @@ -0,0 +1,209 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class ArrayInitializer extends Expression { + + public Expression[] expressions; + public ArrayBinding binding; //the type of the { , , , } + + /** + * ArrayInitializer constructor comment. + */ + public ArrayInitializer() { + + super(); + } + + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + + if (expressions != null) { + for (int i = 0, max = expressions.length; i < max; i++) { + flowInfo = expressions[i].analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); + } + } + return flowInfo; + } + + /** + * Code generation for a array initializer + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { + + // Flatten the values and compute the dimensions, by iterating in depth into nested array initializers + int pc = codeStream.position; + int expressionLength = (expressions == null) ? 0: expressions.length; + codeStream.generateInlinedValue(expressionLength); + codeStream.newArray(currentScope, binding); + if (expressions != null) { + // binding is an ArrayType, so I can just deal with the dimension + int elementsTypeID = binding.dimensions > 1 ? -1 : binding.leafComponentType.id; + for (int i = 0; i < expressionLength; i++) { + Expression expr; + if ((expr = expressions[i]).constant != NotAConstant) { + switch (elementsTypeID) { // filter out initializations to default values + case T_int : + case T_short : + case T_byte : + case T_char : + case T_long : + if (expr.constant.longValue() != 0) { + codeStream.dup(); + codeStream.generateInlinedValue(i); + expr.generateCode(currentScope, codeStream, true); + codeStream.arrayAtPut(elementsTypeID, false); + } + break; + case T_float : + case T_double : + double constantValue = expr.constant.doubleValue(); + if (constantValue == -0.0 || constantValue != 0) { + codeStream.dup(); + codeStream.generateInlinedValue(i); + expr.generateCode(currentScope, codeStream, true); + codeStream.arrayAtPut(elementsTypeID, false); + } + break; + case T_boolean : + if (expr.constant.booleanValue() != false) { + codeStream.dup(); + codeStream.generateInlinedValue(i); + expr.generateCode(currentScope, codeStream, true); + codeStream.arrayAtPut(elementsTypeID, false); + } + break; + default : + if (!(expr instanceof NullLiteral)) { + codeStream.dup(); + codeStream.generateInlinedValue(i); + expr.generateCode(currentScope, codeStream, true); + codeStream.arrayAtPut(elementsTypeID, false); + } + } + } else if (!(expr instanceof NullLiteral)) { + codeStream.dup(); + codeStream.generateInlinedValue(i); + expr.generateCode(currentScope, codeStream, true); + codeStream.arrayAtPut(elementsTypeID, false); + } + } + } + if (!valueRequired) { + codeStream.pop(); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public StringBuffer printExpression(int indent, StringBuffer output) { + + output.append('{'); + if (expressions != null) { + int j = 20 ; + for (int i = 0 ; i < expressions.length ; i++) { + if (i > 0) output.append(", "); //$NON-NLS-1$ + expressions[i].printExpression(0, output); + j -- ; + if (j == 0) { + output.append('\n'); + printIndent(indent+1, output); + j = 20; + } + } + } + return output.append('}'); + } + + public TypeBinding resolveTypeExpecting(BlockScope scope, TypeBinding expectedTb) { + // Array initializers can only occur on the right hand side of an assignment + // expression, therefore the expected type contains the valid information + // concerning the type that must be enforced by the elements of the array initializer. + + // this method is recursive... (the test on isArrayType is the stop case) + + constant = NotAConstant; + if (expectedTb.isArrayType()) { + binding = (ArrayBinding) expectedTb; + if (expressions == null) + return binding; + TypeBinding expectedElementsTb = binding.elementsType(scope); + if (expectedElementsTb.isBaseType()) { + for (int i = 0, length = expressions.length; i < length; i++) { + Expression expression = expressions[i]; + TypeBinding expressionTb = + (expression instanceof ArrayInitializer) + ? expression.resolveTypeExpecting(scope, expectedElementsTb) + : expression.resolveType(scope); + if (expressionTb == null) + return null; + + // Compile-time conversion required? + if (expression.isConstantValueOfTypeAssignableToType(expressionTb, expectedElementsTb)) { + expression.implicitWidening(expectedElementsTb, expressionTb); + } else if (BaseTypeBinding.isWidening(expectedElementsTb.id, expressionTb.id)) { + expression.implicitWidening(expectedElementsTb, expressionTb); + } else { + scope.problemReporter().typeMismatchErrorActualTypeExpectedType(expression, expressionTb, expectedElementsTb); + return null; + } + } + } else { + for (int i = 0, length = expressions.length; i < length; i++) + if (expressions[i].resolveTypeExpecting(scope, expectedElementsTb) == null) + return null; + } + return binding; + } + + // infer initializer type for error reporting based on first element + TypeBinding leafElementType = null; + int dim = 1; + if (expressions == null) { + leafElementType = scope.getJavaLangObject(); + } else { + Expression currentExpression = expressions[0]; + while(currentExpression != null && currentExpression instanceof ArrayInitializer) { + dim++; + Expression[] subExprs = ((ArrayInitializer) currentExpression).expressions; + if (subExprs == null){ + leafElementType = scope.getJavaLangObject(); + currentExpression = null; + break; + } + currentExpression = ((ArrayInitializer) currentExpression).expressions[0]; + } + if (currentExpression != null) { + leafElementType = currentExpression.resolveType(scope); + } + } + if (leafElementType != null) { + TypeBinding probableTb = scope.createArray(leafElementType, dim); + scope.problemReporter().typeMismatchErrorActualTypeExpectedType(this, probableTb, expectedTb); + } + return null; + } + + public void traverse(ASTVisitor visitor, BlockScope scope) { + + if (visitor.visit(this, scope)) { + if (expressions != null) { + int expressionsLength = expressions.length; + for (int i = 0; i < expressionsLength; i++) + expressions[i].traverse(visitor, scope); + } + } + visitor.endVisit(this, scope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/ArrayQualifiedTypeReference.java b/src/java/org/eclipse/jdt/internal/compiler/ast/ArrayQualifiedTypeReference.java new file mode 100644 index 0000000..701f3a6 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/ArrayQualifiedTypeReference.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class ArrayQualifiedTypeReference extends QualifiedTypeReference { + int dimensions; + + public ArrayQualifiedTypeReference(char[][] sources , int dim, long[] poss) { + + super( sources , poss); + dimensions = dim ; + } + + public ArrayQualifiedTypeReference(char[][] sources , TypeBinding tb, int dim, long[] poss) { + + super( sources , tb, poss); + dimensions = dim ; + } + + public int dimensions() { + + return dimensions; + } + + public TypeBinding getTypeBinding(Scope scope) { + + if (this.resolvedType != null) + return this.resolvedType; + if (dimensions > 255) { + scope.problemReporter().tooManyDimensions(this); + } + return scope.createArray(scope.getType(tokens), dimensions); + } + + public StringBuffer printExpression(int indent, StringBuffer output){ + + super.printExpression(indent, output); + for (int i = 0 ; i < dimensions ; i++) { + output.append("[]"); //$NON-NLS-1$ + } + return output; + } + + public void traverse(ASTVisitor visitor, BlockScope scope) { + + visitor.visit(this, scope); + visitor.endVisit(this, scope); + } + + public void traverse(ASTVisitor visitor, ClassScope scope) { + + visitor.visit(this, scope); + visitor.endVisit(this, scope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/ArrayReference.java b/src/java/org/eclipse/jdt/internal/compiler/ast/ArrayReference.java new file mode 100644 index 0000000..915b347 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/ArrayReference.java @@ -0,0 +1,212 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class ArrayReference extends Reference { + + public Expression receiver; + public Expression position; + + public ArrayReference(Expression rec, Expression pos) { + this.receiver = rec; + this.position = pos; + sourceStart = rec.sourceStart; + } + + public FlowInfo analyseAssignment( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo, + Assignment assignment, + boolean compoundAssignment) { + + if (assignment.expression == null) { + return analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); + } + return assignment + .expression + .analyseCode( + currentScope, + flowContext, + analyseCode(currentScope, flowContext, flowInfo).unconditionalInits()) + .unconditionalInits(); + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + return position.analyseCode( + currentScope, + flowContext, + receiver.analyseCode(currentScope, flowContext, flowInfo)); + } + + public void generateAssignment( + BlockScope currentScope, + CodeStream codeStream, + Assignment assignment, + boolean valueRequired) { + + receiver.generateCode(currentScope, codeStream, true); + if (receiver instanceof CastExpression // ((type[])null)[0] + && ((CastExpression)receiver).innermostCastedExpression().resolvedType == NullBinding){ + codeStream.checkcast(receiver.resolvedType); + } + position.generateCode(currentScope, codeStream, true); + assignment.expression.generateCode(currentScope, codeStream, true); + codeStream.arrayAtPut(this.resolvedType.id, valueRequired); + if (valueRequired) { + codeStream.generateImplicitConversion(assignment.implicitConversion); + } + } + + /** + * Code generation for a array reference + */ + public void generateCode( + BlockScope currentScope, + CodeStream codeStream, + boolean valueRequired) { + + int pc = codeStream.position; + receiver.generateCode(currentScope, codeStream, true); + if (receiver instanceof CastExpression // ((type[])null)[0] + && ((CastExpression)receiver).innermostCastedExpression().resolvedType == NullBinding){ + codeStream.checkcast(receiver.resolvedType); + } + position.generateCode(currentScope, codeStream, true); + codeStream.arrayAt(this.resolvedType.id); + // Generating code for the potential runtime type checking + if (valueRequired) { + codeStream.generateImplicitConversion(implicitConversion); + } else { + if (this.resolvedType == LongBinding + || this.resolvedType == DoubleBinding) { + codeStream.pop2(); + } else { + codeStream.pop(); + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public void generateCompoundAssignment( + BlockScope currentScope, + CodeStream codeStream, + Expression expression, + int operator, + int assignmentImplicitConversion, + boolean valueRequired) { + + receiver.generateCode(currentScope, codeStream, true); + if (receiver instanceof CastExpression // ((type[])null)[0] + && ((CastExpression)receiver).innermostCastedExpression().resolvedType == NullBinding){ + codeStream.checkcast(receiver.resolvedType); + } + position.generateCode(currentScope, codeStream, true); + codeStream.dup2(); + codeStream.arrayAt(this.resolvedType.id); + int operationTypeID; + if ((operationTypeID = implicitConversion >> 4) == T_String) { + codeStream.generateStringAppend(currentScope, null, expression); + } else { + // promote the array reference to the suitable operation type + codeStream.generateImplicitConversion(implicitConversion); + // generate the increment value (will by itself be promoted to the operation value) + if (expression == IntLiteral.One) { // prefix operation + codeStream.generateConstant(expression.constant, implicitConversion); + } else { + expression.generateCode(currentScope, codeStream, true); + } + // perform the operation + codeStream.sendOperator(operator, operationTypeID); + // cast the value back to the array reference type + codeStream.generateImplicitConversion(assignmentImplicitConversion); + } + codeStream.arrayAtPut(this.resolvedType.id, valueRequired); + } + + public void generatePostIncrement( + BlockScope currentScope, + CodeStream codeStream, + CompoundAssignment postIncrement, + boolean valueRequired) { + + receiver.generateCode(currentScope, codeStream, true); + if (receiver instanceof CastExpression // ((type[])null)[0] + && ((CastExpression)receiver).innermostCastedExpression().resolvedType == NullBinding){ + codeStream.checkcast(receiver.resolvedType); + } + position.generateCode(currentScope, codeStream, true); + codeStream.dup2(); + codeStream.arrayAt(this.resolvedType.id); + if (valueRequired) { + if ((this.resolvedType == LongBinding) + || (this.resolvedType == DoubleBinding)) { + codeStream.dup2_x2(); + } else { + codeStream.dup_x2(); + } + } + codeStream.generateConstant( + postIncrement.expression.constant, + implicitConversion); + codeStream.sendOperator(postIncrement.operator, this.resolvedType.id); + codeStream.generateImplicitConversion( + postIncrement.assignmentImplicitConversion); + codeStream.arrayAtPut(this.resolvedType.id, false); + } + + public StringBuffer printExpression(int indent, StringBuffer output) { + + receiver.printExpression(0, output).append('['); + return position.printExpression(0, output).append(']'); + } + + public TypeBinding resolveType(BlockScope scope) { + + constant = Constant.NotAConstant; + if (receiver instanceof CastExpression // no cast check for ((type[])null)[0] + && ((CastExpression)receiver).innermostCastedExpression() instanceof NullLiteral) { + this.receiver.bits |= IgnoreNeedForCastCheckMASK; // will check later on + } + TypeBinding arrayType = receiver.resolveType(scope); + if (arrayType != null) { + if (arrayType.isArrayType()) { + this.resolvedType = ((ArrayBinding) arrayType).elementsType(scope); + } else { + scope.problemReporter().referenceMustBeArrayTypeAt(arrayType, this); + } + } + TypeBinding positionType = position.resolveTypeExpecting(scope, IntBinding); + if (positionType != null) { + position.implicitWidening(IntBinding, positionType); + } + return this.resolvedType; + } + + public void traverse(ASTVisitor visitor, BlockScope scope) { + + if (visitor.visit(this, scope)) { + receiver.traverse(visitor, scope); + position.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/ArrayTypeReference.java b/src/java/org/eclipse/jdt/internal/compiler/ast/ArrayTypeReference.java new file mode 100644 index 0000000..eec8865 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/ArrayTypeReference.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class ArrayTypeReference extends SingleTypeReference { + public int dimensions; + + /** + * ArrayTypeReference constructor comment. + * @param source char[] + * @param dimensions int + * @param pos int + */ + public ArrayTypeReference(char[] source, int dimensions, long pos) { + + super(source, pos); + this.dimensions = dimensions ; + } + + public ArrayTypeReference(char[] source, TypeBinding tb, int dimensions, long pos) { + + super(source, tb, pos); + this.dimensions = dimensions ; + } + + public int dimensions() { + + return dimensions; + } + + public TypeBinding getTypeBinding(Scope scope) { + + if (this.resolvedType != null) return this.resolvedType; + if (dimensions > 255) { + scope.problemReporter().tooManyDimensions(this); + } + return scope.createArray(scope.getType(token), dimensions); + + } + + public StringBuffer printExpression(int indent, StringBuffer output){ + + super.printExpression(indent, output) ; + for (int i= 0 ; i < dimensions ; i++) { + output.append("[]"); //$NON-NLS-1$ + } + return output; + } + + public void traverse(ASTVisitor visitor, BlockScope scope) { + + visitor.visit(this, scope); + visitor.endVisit(this, scope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/AssertStatement.java b/src/java/org/eclipse/jdt/internal/compiler/ast/AssertStatement.java new file mode 100644 index 0000000..cf3093a --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/AssertStatement.java @@ -0,0 +1,197 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.impl.Constant; +import org.eclipse.jdt.internal.compiler.lookup.*; +import org.eclipse.jdt.internal.compiler.ASTVisitor; + +public class AssertStatement extends Statement { + + public Expression assertExpression, exceptionArgument; + + // for local variable attribute + int preAssertInitStateIndex = -1; + private FieldBinding assertionSyntheticFieldBinding; + + public AssertStatement( + Expression exceptionArgument, + Expression assertExpression, + int startPosition) { + + this.assertExpression = assertExpression; + this.exceptionArgument = exceptionArgument; + sourceStart = startPosition; + sourceEnd = exceptionArgument.sourceEnd; + } + + public AssertStatement(Expression assertExpression, int startPosition) { + + this.assertExpression = assertExpression; + sourceStart = startPosition; + sourceEnd = assertExpression.sourceEnd; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + preAssertInitStateIndex = currentScope.methodScope().recordInitializationStates(flowInfo); + + Constant cst = this.assertExpression.optimizedBooleanConstant(); + boolean isOptimizedTrueAssertion = cst != NotAConstant && cst.booleanValue() == true; + boolean isOptimizedFalseAssertion = cst != NotAConstant && cst.booleanValue() == false; + + FlowInfo assertInfo = flowInfo.copy(); + if (isOptimizedTrueAssertion) { + assertInfo.setReachMode(FlowInfo.UNREACHABLE); + } + assertInfo = assertExpression.analyseCode(currentScope, flowContext, assertInfo).unconditionalInits(); + + if (exceptionArgument != null) { + // only gets evaluated when escaping - results are not taken into account + FlowInfo exceptionInfo = exceptionArgument.analyseCode(currentScope, flowContext, assertInfo.copy()); + + if (!isOptimizedTrueAssertion){ + flowContext.checkExceptionHandlers( + currentScope.getJavaLangAssertionError(), + this, + exceptionInfo, + currentScope); + } + } + + if (!isOptimizedTrueAssertion){ + // add the assert support in the clinit + manageSyntheticAccessIfNecessary(currentScope, flowInfo); + } + if (isOptimizedFalseAssertion) { + return flowInfo; // if assertions are enabled, the following code will be unreachable + } else { + return flowInfo.mergedWith(assertInfo.unconditionalInits()); + } + } + + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + + if ((bits & IsReachableMASK) == 0) { + return; + } + int pc = codeStream.position; + + if (this.assertionSyntheticFieldBinding != null) { + Label assertionActivationLabel = new Label(codeStream); + codeStream.getstatic(this.assertionSyntheticFieldBinding); + codeStream.ifne(assertionActivationLabel); + + Label falseLabel = new Label(codeStream); + this.assertExpression.generateOptimizedBoolean(currentScope, codeStream, (falseLabel = new Label(codeStream)), null , true); + codeStream.newJavaLangAssertionError(); + codeStream.dup(); + if (exceptionArgument != null) { + exceptionArgument.generateCode(currentScope, codeStream, true); + codeStream.invokeJavaLangAssertionErrorConstructor(exceptionArgument.implicitConversion & 0xF); + } else { + codeStream.invokeJavaLangAssertionErrorDefaultConstructor(); + } + codeStream.athrow(); + falseLabel.place(); + assertionActivationLabel.place(); + } + + // May loose some local variable initializations : affecting the local variable attributes + if (preAssertInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables(currentScope, preAssertInitStateIndex); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public void resolve(BlockScope scope) { + + assertExpression.resolveTypeExpecting(scope, BooleanBinding); + if (exceptionArgument != null) { + TypeBinding exceptionArgumentType = exceptionArgument.resolveType(scope); + if (exceptionArgumentType != null){ + int id = exceptionArgumentType.id; + switch(id) { + case T_void : + scope.problemReporter().illegalVoidExpression(exceptionArgument); + default: + id = T_Object; + case T_boolean : + case T_byte : + case T_char : + case T_short : + case T_double : + case T_float : + case T_int : + case T_long : + case T_String : + exceptionArgument.implicitConversion = (id << 4) + id; + } + } + } + } + + public void traverse(ASTVisitor visitor, BlockScope scope) { + + if (visitor.visit(this, scope)) { + assertExpression.traverse(visitor, scope); + if (exceptionArgument != null) { + exceptionArgument.traverse(visitor, scope); + } + } + visitor.endVisit(this, scope); + } + + public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) { + + if (!flowInfo.isReachable()) return; + + // need assertion flag: $assertionsDisabled on outer most source clas + // (in case of static member of interface, will use the outermost static member - bug 22334) + SourceTypeBinding outerMostClass = currentScope.enclosingSourceType(); + while (outerMostClass.isLocalType()){ + ReferenceBinding enclosing = outerMostClass.enclosingType(); + if (enclosing == null || enclosing.isInterface()) break; + outerMostClass = (SourceTypeBinding) enclosing; + } + + this.assertionSyntheticFieldBinding = outerMostClass.addSyntheticField(this, currentScope); + + // find and enable assertion support + TypeDeclaration typeDeclaration = outerMostClass.scope.referenceType(); + AbstractMethodDeclaration[] methods = typeDeclaration.methods; + for (int i = 0, max = methods.length; i < max; i++) { + AbstractMethodDeclaration method = methods[i]; + if (method.isClinit()) { + ((Clinit) method).setAssertionSupport(assertionSyntheticFieldBinding); + break; + } + } + } + + public StringBuffer printStatement(int tab, StringBuffer output) { + + printIndent(tab, output); + output.append("assert "); //$NON-NLS-1$ + this.assertExpression.printExpression(0, output); + if (this.exceptionArgument != null) { + output.append(": "); //$NON-NLS-1$ + this.exceptionArgument.printExpression(0, output); + } + return output.append(';'); + } + +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/Assignment.java b/src/java/org/eclipse/jdt/internal/compiler/ast/Assignment.java new file mode 100644 index 0000000..5b86ade --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/Assignment.java @@ -0,0 +1,172 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Genady Beriozkin - added support for reporting assignment with no effect + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class Assignment extends Expression { + + public Expression lhs; + public Expression expression; + + public Assignment(Expression lhs, Expression expression, int sourceEnd) { + //lhs is always a reference by construction , + //but is build as an expression ==> the checkcast cannot fail + + this.lhs = lhs; + lhs.bits |= IsStrictlyAssignedMASK; // tag lhs as assigned + + this.expression = expression; + + this.sourceStart = lhs.sourceStart; + this.sourceEnd = sourceEnd; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + // record setting a variable: various scenarii are possible, setting an array reference, + // a field reference, a blank final field reference, a field of an enclosing instance or + // just a local variable. + + return ((Reference) lhs) + .analyseAssignment(currentScope, flowContext, flowInfo, this, false) + .unconditionalInits(); + } + + void checkAssignmentEffect(BlockScope scope) { + + Binding left = getDirectBinding(this.lhs); + if (left != null && left == getDirectBinding(this.expression)) { + scope.problemReporter().assignmentHasNoEffect(this, left.shortReadableName()); + this.bits |= IsAssignmentWithNoEffectMASK; // record assignment has no effect + } + } + + public void generateCode( + BlockScope currentScope, + CodeStream codeStream, + boolean valueRequired) { + + // various scenarii are possible, setting an array reference, + // a field reference, a blank final field reference, a field of an enclosing instance or + // just a local variable. + + int pc = codeStream.position; + if ((this.bits & IsAssignmentWithNoEffectMASK) != 0) { + if (valueRequired) { + this.expression.generateCode(currentScope, codeStream, true); + } + } else { + ((Reference) lhs).generateAssignment(currentScope, codeStream, this, valueRequired); + // variable may have been optimized out + // the lhs is responsible to perform the implicitConversion generation for the assignment since optimized for unused local assignment. + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + Binding getDirectBinding(Expression someExpression) { + if (someExpression instanceof SingleNameReference) { + return ((SingleNameReference)someExpression).binding; + } else if (someExpression instanceof FieldReference) { + FieldReference fieldRef = (FieldReference)someExpression; + if (fieldRef.receiver.isThis() && !(fieldRef.receiver instanceof QualifiedThisReference)) { + return fieldRef.binding; + } + } + return null; + } + public StringBuffer print(int indent, StringBuffer output) { + + //no () when used as a statement + printIndent(indent, output); + return printExpressionNoParenthesis(indent, output); + } + public StringBuffer printExpression(int indent, StringBuffer output) { + + //subclass redefine printExpressionNoParenthesis() + output.append('('); + return printExpressionNoParenthesis(0, output).append(')'); + } + + public StringBuffer printExpressionNoParenthesis(int indent, StringBuffer output) { + + lhs.printExpression(indent, output).append(" = "); //$NON-NLS-1$ + return expression.printExpression(0, output); + } + + public StringBuffer printStatement(int indent, StringBuffer output) { + + //no () when used as a statement + return print(indent, output).append(';'); + } + + public TypeBinding resolveType(BlockScope scope) { + + // due to syntax lhs may be only a NameReference, a FieldReference or an ArrayReference + constant = NotAConstant; + if (!(this.lhs instanceof Reference) || this.lhs.isThis()) { + scope.problemReporter().expressionShouldBeAVariable(this.lhs); + return null; + } + this.resolvedType = lhs.resolveType(scope); // expressionType contains the assignment type (lhs Type) + TypeBinding rhsType = expression.resolveType(scope); + if (this.resolvedType == null || rhsType == null) { + return null; + } + checkAssignmentEffect(scope); + + // Compile-time conversion of base-types : implicit narrowing integer into byte/short/character + // may require to widen the rhs expression at runtime + if ((expression.isConstantValueOfTypeAssignableToType(rhsType, this.resolvedType) + || (this.resolvedType.isBaseType() && BaseTypeBinding.isWidening(this.resolvedType.id, rhsType.id))) + || rhsType.isCompatibleWith(this.resolvedType)) { + expression.implicitWidening(this.resolvedType, rhsType); + return this.resolvedType; + } + scope.problemReporter().typeMismatchErrorActualTypeExpectedType( + expression, + rhsType, + this.resolvedType); + return this.resolvedType; + } + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.ast.Expression#resolveTypeExpecting(org.eclipse.jdt.internal.compiler.lookup.BlockScope, org.eclipse.jdt.internal.compiler.lookup.TypeBinding) + */ + public TypeBinding resolveTypeExpecting( + BlockScope scope, + TypeBinding expectedType) { + + TypeBinding type = super.resolveTypeExpecting(scope, expectedType); + // signal possible accidental boolean assignment (instead of using '==' operator) + if (expectedType == BooleanBinding + && this.lhs.resolvedType == BooleanBinding + && (this.lhs.bits & IsStrictlyAssignedMASK) != 0) { + scope.problemReporter().possibleAccidentalBooleanAssignment(this); + } + + return type; + } + + public void traverse(ASTVisitor visitor, BlockScope scope) { + + if (visitor.visit(this, scope)) { + lhs.traverse(visitor, scope); + expression.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +} \ No newline at end of file diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java b/src/java/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java new file mode 100644 index 0000000..b5804d0 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java @@ -0,0 +1,1761 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class BinaryExpression extends OperatorExpression { + + public Expression left, right; + public Constant optimizedBooleanConstant; + + public BinaryExpression(Expression left, Expression right, int operator) { + + this.left = left; + this.right = right; + this.bits |= operator << OperatorSHIFT; // encode operator + this.sourceStart = left.sourceStart; + this.sourceEnd = right.sourceEnd; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + return right + .analyseCode( + currentScope, + flowContext, + left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits()) + .unconditionalInits(); + } + + public void computeConstant(BlockScope scope, int leftId, int rightId) { + + //compute the constant when valid + if ((this.left.constant != Constant.NotAConstant) + && (this.right.constant != Constant.NotAConstant)) { + try { + this.constant = + Constant.computeConstantOperation( + this.left.constant, + leftId, + (this.bits & OperatorMASK) >> OperatorSHIFT, + this.right.constant, + rightId); + } catch (ArithmeticException e) { + this.constant = Constant.NotAConstant; + // 1.2 no longer throws an exception at compile-time + //scope.problemReporter().compileTimeConstantThrowsArithmeticException(this); + } + } else { + this.constant = Constant.NotAConstant; + //add some work for the boolean operators & | + this.optimizedBooleanConstant( + leftId, + (this.bits & OperatorMASK) >> OperatorSHIFT, + rightId); + } + } + + public Constant optimizedBooleanConstant() { + + return this.optimizedBooleanConstant == null ? this.constant : this.optimizedBooleanConstant; + } + + /** + * Code generation for a binary operation + */ + public void generateCode( + BlockScope currentScope, + CodeStream codeStream, + boolean valueRequired) { + + int pc = codeStream.position; + Label falseLabel, endLabel; + if (constant != Constant.NotAConstant) { + if (valueRequired) + codeStream.generateConstant(constant, implicitConversion); + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + bits |= OnlyValueRequiredMASK; + switch ((bits & OperatorMASK) >> OperatorSHIFT) { + case PLUS : + switch (bits & ReturnTypeIDMASK) { + case T_String : + codeStream.generateStringAppend(currentScope, left, right); + if (!valueRequired) + codeStream.pop(); + break; + case T_int : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.iadd(); + break; + case T_long : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.ladd(); + break; + case T_double : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.dadd(); + break; + case T_float : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.fadd(); + break; + } + break; + case MINUS : + switch (bits & ReturnTypeIDMASK) { + case T_int : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.isub(); + break; + case T_long : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.lsub(); + break; + case T_double : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.dsub(); + break; + case T_float : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.fsub(); + break; + } + break; + case MULTIPLY : + switch (bits & ReturnTypeIDMASK) { + case T_int : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.imul(); + break; + case T_long : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.lmul(); + break; + case T_double : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.dmul(); + break; + case T_float : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.fmul(); + break; + } + break; + case DIVIDE : + switch (bits & ReturnTypeIDMASK) { + case T_int : + left.generateCode(currentScope, codeStream, true); + right.generateCode(currentScope, codeStream, true); + codeStream.idiv(); + if (!valueRequired) + codeStream.pop(); + break; + case T_long : + left.generateCode(currentScope, codeStream, true); + right.generateCode(currentScope, codeStream, true); + codeStream.ldiv(); + if (!valueRequired) + codeStream.pop2(); + break; + case T_double : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.ddiv(); + break; + case T_float : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.fdiv(); + break; + } + break; + case REMAINDER : + switch (bits & ReturnTypeIDMASK) { + case T_int : + left.generateCode(currentScope, codeStream, true); + right.generateCode(currentScope, codeStream, true); + codeStream.irem(); + if (!valueRequired) + codeStream.pop(); + break; + case T_long : + left.generateCode(currentScope, codeStream, true); + right.generateCode(currentScope, codeStream, true); + codeStream.lrem(); + if (!valueRequired) + codeStream.pop2(); + break; + case T_double : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.drem(); + break; + case T_float : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.frem(); + break; + } + break; + case AND : + switch (bits & ReturnTypeIDMASK) { + case T_int : + // 0 & x + if ((left.constant != Constant.NotAConstant) + && (left.constant.typeID() == T_int) + && (left.constant.intValue() == 0)) { + right.generateCode(currentScope, codeStream, false); + if (valueRequired) + codeStream.iconst_0(); + } else { + // x & 0 + if ((right.constant != Constant.NotAConstant) + && (right.constant.typeID() == T_int) + && (right.constant.intValue() == 0)) { + left.generateCode(currentScope, codeStream, false); + if (valueRequired) + codeStream.iconst_0(); + } else { + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.iand(); + } + } + break; + case T_long : + // 0 & x + if ((left.constant != Constant.NotAConstant) + && (left.constant.typeID() == T_long) + && (left.constant.longValue() == 0L)) { + right.generateCode(currentScope, codeStream, false); + if (valueRequired) + codeStream.lconst_0(); + } else { + // x & 0 + if ((right.constant != Constant.NotAConstant) + && (right.constant.typeID() == T_long) + && (right.constant.longValue() == 0L)) { + left.generateCode(currentScope, codeStream, false); + if (valueRequired) + codeStream.lconst_0(); + } else { + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.land(); + } + } + break; + case T_boolean : // logical and + generateOptimizedLogicalAnd( + currentScope, + codeStream, + null, + (falseLabel = new Label(codeStream)), + valueRequired); + /* improving code gen for such a case: boolean b = i < 0 && false; + * since the label has never been used, we have the inlined value on the stack. */ + if (falseLabel.hasForwardReferences()) { + if (valueRequired) { + codeStream.iconst_1(); + if ((bits & ValueForReturnMASK) != 0) { + codeStream.ireturn(); + falseLabel.place(); + codeStream.iconst_0(); + } else { + codeStream.goto_(endLabel = new Label(codeStream)); + codeStream.decrStackSize(1); + falseLabel.place(); + codeStream.iconst_0(); + endLabel.place(); + } + } else { + falseLabel.place(); + } + } + } + break; + case OR : + switch (bits & ReturnTypeIDMASK) { + case T_int : + // 0 | x + if ((left.constant != Constant.NotAConstant) + && (left.constant.typeID() == T_int) + && (left.constant.intValue() == 0)) { + right.generateCode(currentScope, codeStream, valueRequired); + } else { + // x | 0 + if ((right.constant != Constant.NotAConstant) + && (right.constant.typeID() == T_int) + && (right.constant.intValue() == 0)) { + left.generateCode(currentScope, codeStream, valueRequired); + } else { + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.ior(); + } + } + break; + case T_long : + // 0 | x + if ((left.constant != Constant.NotAConstant) + && (left.constant.typeID() == T_long) + && (left.constant.longValue() == 0L)) { + right.generateCode(currentScope, codeStream, valueRequired); + } else { + // x | 0 + if ((right.constant != Constant.NotAConstant) + && (right.constant.typeID() == T_long) + && (right.constant.longValue() == 0L)) { + left.generateCode(currentScope, codeStream, valueRequired); + } else { + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.lor(); + } + } + break; + case T_boolean : // logical or + generateOptimizedLogicalOr( + currentScope, + codeStream, + null, + (falseLabel = new Label(codeStream)), + valueRequired); + /* improving code gen for such a case: boolean b = i < 0 || true; + * since the label has never been used, we have the inlined value on the stack. */ + if (falseLabel.hasForwardReferences()) { + if (valueRequired) { + codeStream.iconst_1(); + if ((bits & ValueForReturnMASK) != 0) { + codeStream.ireturn(); + falseLabel.place(); + codeStream.iconst_0(); + } else { + codeStream.goto_(endLabel = new Label(codeStream)); + codeStream.decrStackSize(1); + falseLabel.place(); + codeStream.iconst_0(); + endLabel.place(); + } + } else { + falseLabel.place(); + } + } + } + break; + case XOR : + switch (bits & ReturnTypeIDMASK) { + case T_int : + // 0 ^ x + if ((left.constant != Constant.NotAConstant) + && (left.constant.typeID() == T_int) + && (left.constant.intValue() == 0)) { + right.generateCode(currentScope, codeStream, valueRequired); + } else { + // x ^ 0 + if ((right.constant != Constant.NotAConstant) + && (right.constant.typeID() == T_int) + && (right.constant.intValue() == 0)) { + left.generateCode(currentScope, codeStream, valueRequired); + } else { + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.ixor(); + } + } + break; + case T_long : + // 0 ^ x + if ((left.constant != Constant.NotAConstant) + && (left.constant.typeID() == T_long) + && (left.constant.longValue() == 0L)) { + right.generateCode(currentScope, codeStream, valueRequired); + } else { + // x ^ 0 + if ((right.constant != Constant.NotAConstant) + && (right.constant.typeID() == T_long) + && (right.constant.longValue() == 0L)) { + left.generateCode(currentScope, codeStream, valueRequired); + } else { + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.lxor(); + } + } + break; + case T_boolean : + generateOptimizedLogicalXor( + currentScope, + codeStream, + null, + (falseLabel = new Label(codeStream)), + valueRequired); + /* improving code gen for such a case: boolean b = i < 0 ^ bool; + * since the label has never been used, we have the inlined value on the stack. */ + if (falseLabel.hasForwardReferences()) { + if (valueRequired) { + codeStream.iconst_1(); + if ((bits & ValueForReturnMASK) != 0) { + codeStream.ireturn(); + falseLabel.place(); + codeStream.iconst_0(); + } else { + codeStream.goto_(endLabel = new Label(codeStream)); + codeStream.decrStackSize(1); + falseLabel.place(); + codeStream.iconst_0(); + endLabel.place(); + } + } else { + falseLabel.place(); + } + } + } + break; + case LEFT_SHIFT : + switch (bits & ReturnTypeIDMASK) { + case T_int : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.ishl(); + break; + case T_long : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.lshl(); + } + break; + case RIGHT_SHIFT : + switch (bits & ReturnTypeIDMASK) { + case T_int : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.ishr(); + break; + case T_long : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.lshr(); + } + break; + case UNSIGNED_RIGHT_SHIFT : + switch (bits & ReturnTypeIDMASK) { + case T_int : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.iushr(); + break; + case T_long : + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) + codeStream.lushr(); + } + break; + case GREATER : + generateOptimizedGreaterThan( + currentScope, + codeStream, + null, + (falseLabel = new Label(codeStream)), + valueRequired); + if (valueRequired) { + codeStream.iconst_1(); + if ((bits & ValueForReturnMASK) != 0) { + codeStream.ireturn(); + falseLabel.place(); + codeStream.iconst_0(); + } else { + codeStream.goto_(endLabel = new Label(codeStream)); + codeStream.decrStackSize(1); + falseLabel.place(); + codeStream.iconst_0(); + endLabel.place(); + } + } + break; + case GREATER_EQUAL : + generateOptimizedGreaterThanOrEqual( + currentScope, + codeStream, + null, + (falseLabel = new Label(codeStream)), + valueRequired); + if (valueRequired) { + codeStream.iconst_1(); + if ((bits & ValueForReturnMASK) != 0) { + codeStream.ireturn(); + falseLabel.place(); + codeStream.iconst_0(); + } else { + codeStream.goto_(endLabel = new Label(codeStream)); + codeStream.decrStackSize(1); + falseLabel.place(); + codeStream.iconst_0(); + endLabel.place(); + } + } + break; + case LESS : + generateOptimizedLessThan( + currentScope, + codeStream, + null, + (falseLabel = new Label(codeStream)), + valueRequired); + if (valueRequired) { + codeStream.iconst_1(); + if ((bits & ValueForReturnMASK) != 0) { + codeStream.ireturn(); + falseLabel.place(); + codeStream.iconst_0(); + } else { + codeStream.goto_(endLabel = new Label(codeStream)); + codeStream.decrStackSize(1); + falseLabel.place(); + codeStream.iconst_0(); + endLabel.place(); + } + } + break; + case LESS_EQUAL : + generateOptimizedLessThanOrEqual( + currentScope, + codeStream, + null, + (falseLabel = new Label(codeStream)), + valueRequired); + if (valueRequired) { + codeStream.iconst_1(); + if ((bits & ValueForReturnMASK) != 0) { + codeStream.ireturn(); + falseLabel.place(); + codeStream.iconst_0(); + } else { + codeStream.goto_(endLabel = new Label(codeStream)); + codeStream.decrStackSize(1); + falseLabel.place(); + codeStream.iconst_0(); + endLabel.place(); + } + } + } + if (valueRequired) { + codeStream.generateImplicitConversion(implicitConversion); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + /** + * Boolean operator code generation + * Optimized operations are: <, <=, >, >=, &, |, ^ + */ + public void generateOptimizedBoolean( + BlockScope currentScope, + CodeStream codeStream, + Label trueLabel, + Label falseLabel, + boolean valueRequired) { + + if ((constant != Constant.NotAConstant) && (constant.typeID() == T_boolean)) { + super.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + return; + } + switch ((bits & OperatorMASK) >> OperatorSHIFT) { + case LESS : + generateOptimizedLessThan( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + return; + case LESS_EQUAL : + generateOptimizedLessThanOrEqual( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + return; + case GREATER : + generateOptimizedGreaterThan( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + return; + case GREATER_EQUAL : + generateOptimizedGreaterThanOrEqual( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + return; + case AND : + generateOptimizedLogicalAnd( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + return; + case OR : + generateOptimizedLogicalOr( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + return; + case XOR : + generateOptimizedLogicalXor( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + return; + } + super.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + } + + /** + * Boolean generation for > + */ + public void generateOptimizedGreaterThan( + BlockScope currentScope, + CodeStream codeStream, + Label trueLabel, + Label falseLabel, + boolean valueRequired) { + + int promotedTypeID = left.implicitConversion >> 4; + // both sides got promoted in the same way + if (promotedTypeID == T_int) { + // 0 > x + if ((left.constant != NotAConstant) && (left.constant.intValue() == 0)) { + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicitly falling through the FALSE case + codeStream.iflt(trueLabel); + } + } else { + if (trueLabel == null) { + // implicitly falling through the TRUE case + codeStream.ifge(falseLabel); + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + // reposition the endPC + codeStream.updateLastRecordedEndPC(codeStream.position); + return; + } + // x > 0 + if ((right.constant != NotAConstant) && (right.constant.intValue() == 0)) { + left.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicitly falling through the FALSE case + codeStream.ifgt(trueLabel); + } + } else { + if (trueLabel == null) { + // implicitly falling through the TRUE case + codeStream.ifle(falseLabel); + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + // reposition the endPC + codeStream.updateLastRecordedEndPC(codeStream.position); + return; + } + } + // default comparison + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicit falling through the FALSE case + switch (promotedTypeID) { + case T_int : + codeStream.if_icmpgt(trueLabel); + break; + case T_float : + codeStream.fcmpl(); + codeStream.ifgt(trueLabel); + break; + case T_long : + codeStream.lcmp(); + codeStream.ifgt(trueLabel); + break; + case T_double : + codeStream.dcmpl(); + codeStream.ifgt(trueLabel); + } + // reposition the endPC + codeStream.updateLastRecordedEndPC(codeStream.position); + return; + } + } else { + if (trueLabel == null) { + // implicit falling through the TRUE case + switch (promotedTypeID) { + case T_int : + codeStream.if_icmple(falseLabel); + break; + case T_float : + codeStream.fcmpl(); + codeStream.ifle(falseLabel); + break; + case T_long : + codeStream.lcmp(); + codeStream.ifle(falseLabel); + break; + case T_double : + codeStream.dcmpl(); + codeStream.ifle(falseLabel); + } + // reposition the endPC + codeStream.updateLastRecordedEndPC(codeStream.position); + return; + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + } + + /** + * Boolean generation for >= + */ + public void generateOptimizedGreaterThanOrEqual( + BlockScope currentScope, + CodeStream codeStream, + Label trueLabel, + Label falseLabel, + boolean valueRequired) { + + int promotedTypeID = left.implicitConversion >> 4; + // both sides got promoted in the same way + if (promotedTypeID == T_int) { + // 0 >= x + if ((left.constant != NotAConstant) && (left.constant.intValue() == 0)) { + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicitly falling through the FALSE case + codeStream.ifle(trueLabel); + } + } else { + if (trueLabel == null) { + // implicitly falling through the TRUE case + codeStream.ifgt(falseLabel); + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + // reposition the endPC + codeStream.updateLastRecordedEndPC(codeStream.position); + return; + } + // x >= 0 + if ((right.constant != NotAConstant) && (right.constant.intValue() == 0)) { + left.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicitly falling through the FALSE case + codeStream.ifge(trueLabel); + } + } else { + if (trueLabel == null) { + // implicitly falling through the TRUE case + codeStream.iflt(falseLabel); + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + // reposition the endPC + codeStream.updateLastRecordedEndPC(codeStream.position); + return; + } + } + // default comparison + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicit falling through the FALSE case + switch (promotedTypeID) { + case T_int : + codeStream.if_icmpge(trueLabel); + break; + case T_float : + codeStream.fcmpl(); + codeStream.ifge(trueLabel); + break; + case T_long : + codeStream.lcmp(); + codeStream.ifge(trueLabel); + break; + case T_double : + codeStream.dcmpl(); + codeStream.ifge(trueLabel); + } + // reposition the endPC + codeStream.updateLastRecordedEndPC(codeStream.position); + return; + } + } else { + if (trueLabel == null) { + // implicit falling through the TRUE case + switch (promotedTypeID) { + case T_int : + codeStream.if_icmplt(falseLabel); + break; + case T_float : + codeStream.fcmpl(); + codeStream.iflt(falseLabel); + break; + case T_long : + codeStream.lcmp(); + codeStream.iflt(falseLabel); + break; + case T_double : + codeStream.dcmpl(); + codeStream.iflt(falseLabel); + } + // reposition the endPC + codeStream.updateLastRecordedEndPC(codeStream.position); + return; + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + } + + /** + * Boolean generation for < + */ + public void generateOptimizedLessThan( + BlockScope currentScope, + CodeStream codeStream, + Label trueLabel, + Label falseLabel, + boolean valueRequired) { + + int promotedTypeID = left.implicitConversion >> 4; + // both sides got promoted in the same way + if (promotedTypeID == T_int) { + // 0 < x + if ((left.constant != NotAConstant) && (left.constant.intValue() == 0)) { + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicitly falling through the FALSE case + codeStream.ifgt(trueLabel); + } + } else { + if (trueLabel == null) { + // implicitly falling through the TRUE case + codeStream.ifle(falseLabel); + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + codeStream.updateLastRecordedEndPC(codeStream.position); + return; + } + // x < 0 + if ((right.constant != NotAConstant) && (right.constant.intValue() == 0)) { + left.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicitly falling through the FALSE case + codeStream.iflt(trueLabel); + } + } else { + if (trueLabel == null) { + // implicitly falling through the TRUE case + codeStream.ifge(falseLabel); + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + codeStream.updateLastRecordedEndPC(codeStream.position); + return; + } + } + // default comparison + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicit falling through the FALSE case + switch (promotedTypeID) { + case T_int : + codeStream.if_icmplt(trueLabel); + break; + case T_float : + codeStream.fcmpg(); + codeStream.iflt(trueLabel); + break; + case T_long : + codeStream.lcmp(); + codeStream.iflt(trueLabel); + break; + case T_double : + codeStream.dcmpg(); + codeStream.iflt(trueLabel); + } + codeStream.updateLastRecordedEndPC(codeStream.position); + return; + } + } else { + if (trueLabel == null) { + // implicit falling through the TRUE case + switch (promotedTypeID) { + case T_int : + codeStream.if_icmpge(falseLabel); + break; + case T_float : + codeStream.fcmpg(); + codeStream.ifge(falseLabel); + break; + case T_long : + codeStream.lcmp(); + codeStream.ifge(falseLabel); + break; + case T_double : + codeStream.dcmpg(); + codeStream.ifge(falseLabel); + } + codeStream.updateLastRecordedEndPC(codeStream.position); + return; + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + } + + /** + * Boolean generation for <= + */ + public void generateOptimizedLessThanOrEqual( + BlockScope currentScope, + CodeStream codeStream, + Label trueLabel, + Label falseLabel, + boolean valueRequired) { + + int promotedTypeID = left.implicitConversion >> 4; + // both sides got promoted in the same way + if (promotedTypeID == T_int) { + // 0 <= x + if ((left.constant != NotAConstant) && (left.constant.intValue() == 0)) { + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicitly falling through the FALSE case + codeStream.ifge(trueLabel); + } + } else { + if (trueLabel == null) { + // implicitly falling through the TRUE case + codeStream.iflt(falseLabel); + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + // reposition the endPC + codeStream.updateLastRecordedEndPC(codeStream.position); + return; + } + // x <= 0 + if ((right.constant != NotAConstant) && (right.constant.intValue() == 0)) { + left.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicitly falling through the FALSE case + codeStream.ifle(trueLabel); + } + } else { + if (trueLabel == null) { + // implicitly falling through the TRUE case + codeStream.ifgt(falseLabel); + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + // reposition the endPC + codeStream.updateLastRecordedEndPC(codeStream.position); + return; + } + } + // default comparison + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicit falling through the FALSE case + switch (promotedTypeID) { + case T_int : + codeStream.if_icmple(trueLabel); + break; + case T_float : + codeStream.fcmpg(); + codeStream.ifle(trueLabel); + break; + case T_long : + codeStream.lcmp(); + codeStream.ifle(trueLabel); + break; + case T_double : + codeStream.dcmpg(); + codeStream.ifle(trueLabel); + } + // reposition the endPC + codeStream.updateLastRecordedEndPC(codeStream.position); + return; + } + } else { + if (trueLabel == null) { + // implicit falling through the TRUE case + switch (promotedTypeID) { + case T_int : + codeStream.if_icmpgt(falseLabel); + break; + case T_float : + codeStream.fcmpg(); + codeStream.ifgt(falseLabel); + break; + case T_long : + codeStream.lcmp(); + codeStream.ifgt(falseLabel); + break; + case T_double : + codeStream.dcmpg(); + codeStream.ifgt(falseLabel); + } + // reposition the endPC + codeStream.updateLastRecordedEndPC(codeStream.position); + return; + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + } + + /** + * Boolean generation for & + */ + public void generateOptimizedLogicalAnd( + BlockScope currentScope, + CodeStream codeStream, + Label trueLabel, + Label falseLabel, + boolean valueRequired) { + + Constant condConst; + if ((left.implicitConversion & 0xF) == T_boolean) { + if ((condConst = left.optimizedBooleanConstant()) != NotAConstant) { + if (condConst.booleanValue() == true) { + // & x + left.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + if ((bits & OnlyValueRequiredMASK) != 0) { + right.generateCode(currentScope, codeStream, valueRequired); + } else { + right.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + } + } else { + // & x + left.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + Label internalTrueLabel = new Label(codeStream); + right.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + internalTrueLabel.place(); + if (valueRequired) { + if ((bits & OnlyValueRequiredMASK) != 0) { + codeStream.iconst_0(); + } else { + if (falseLabel != null) { + // implicit falling through the TRUE case + codeStream.goto_(falseLabel); + } + } + } + // reposition the endPC + codeStream.updateLastRecordedEndPC(codeStream.position); + } + return; + } + if ((condConst = right.optimizedBooleanConstant()) != NotAConstant) { + if (condConst.booleanValue() == true) { + // x & + if ((bits & OnlyValueRequiredMASK) != 0) { + left.generateCode(currentScope, codeStream, valueRequired); + } else { + left.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + } + right.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + } else { + // x & + Label internalTrueLabel = new Label(codeStream); + left.generateOptimizedBoolean( + currentScope, + codeStream, + internalTrueLabel, + falseLabel, + false); + internalTrueLabel.place(); + right.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + if (valueRequired) { + if ((bits & OnlyValueRequiredMASK) != 0) { + codeStream.iconst_0(); + } else { + if (falseLabel != null) { + // implicit falling through the TRUE case + codeStream.goto_(falseLabel); + } + } + } + // reposition the endPC + codeStream.updateLastRecordedEndPC(codeStream.position); + } + return; + } + } + // default case + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + codeStream.iand(); + if ((bits & OnlyValueRequiredMASK) == 0) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicit falling through the FALSE case + codeStream.ifne(trueLabel); + } + } else { + // implicit falling through the TRUE case + if (trueLabel == null) { + codeStream.ifeq(falseLabel); + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + } + // reposition the endPC + codeStream.updateLastRecordedEndPC(codeStream.position); + } + + /** + * Boolean generation for | + */ + public void generateOptimizedLogicalOr( + BlockScope currentScope, + CodeStream codeStream, + Label trueLabel, + Label falseLabel, + boolean valueRequired) { + + Constant condConst; + if ((left.implicitConversion & 0xF) == T_boolean) { + if ((condConst = left.optimizedBooleanConstant()) != NotAConstant) { + if (condConst.booleanValue() == true) { + // | x + left.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + Label internalFalseLabel = new Label(codeStream); + right.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + internalFalseLabel, + false); + internalFalseLabel.place(); + if (valueRequired) { + if ((bits & OnlyValueRequiredMASK) != 0) { + codeStream.iconst_1(); + } else { + if (trueLabel != null) { + codeStream.goto_(trueLabel); + } + } + } + // reposition the endPC + codeStream.updateLastRecordedEndPC(codeStream.position); + } else { + // | x + left.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + if ((bits & OnlyValueRequiredMASK) != 0) { + right.generateCode(currentScope, codeStream, valueRequired); + } else { + right.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + } + } + return; + } + if ((condConst = right.optimizedBooleanConstant()) != NotAConstant) { + if (condConst.booleanValue() == true) { + // x | + Label internalFalseLabel = new Label(codeStream); + left.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + internalFalseLabel, + false); + internalFalseLabel.place(); + right.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + if (valueRequired) { + if ((bits & OnlyValueRequiredMASK) != 0) { + codeStream.iconst_1(); + } else { + if (trueLabel != null) { + codeStream.goto_(trueLabel); + } + } + } + // reposition the endPC + codeStream.updateLastRecordedEndPC(codeStream.position); + } else { + // x | + if ((bits & OnlyValueRequiredMASK) != 0) { + left.generateCode(currentScope, codeStream, valueRequired); + } else { + left.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + } + right.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + } + return; + } + } + // default case + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + codeStream.ior(); + if ((bits & OnlyValueRequiredMASK) == 0) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicit falling through the FALSE case + codeStream.ifne(trueLabel); + } + } else { + // implicit falling through the TRUE case + if (trueLabel == null) { + codeStream.ifeq(falseLabel); + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + } + // reposition the endPC + codeStream.updateLastRecordedEndPC(codeStream.position); + } + + /** + * Boolean generation for ^ + */ + public void generateOptimizedLogicalXor( + BlockScope currentScope, + CodeStream codeStream, + Label trueLabel, + Label falseLabel, + boolean valueRequired) { + + Constant condConst; + if ((left.implicitConversion & 0xF) == T_boolean) { + if ((condConst = left.optimizedBooleanConstant()) != NotAConstant) { + if (condConst.booleanValue() == true) { + // ^ x + left.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + right.generateOptimizedBoolean( + currentScope, + codeStream, + falseLabel, + trueLabel, + valueRequired); + } else { + // ^ x + left.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + if ((bits & OnlyValueRequiredMASK) != 0) { + right.generateCode(currentScope, codeStream, valueRequired); + } else { + right.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + } + } + return; + } + if ((condConst = right.optimizedBooleanConstant()) != NotAConstant) { + if (condConst.booleanValue() == true) { + // x ^ + left.generateOptimizedBoolean( + currentScope, + codeStream, + falseLabel, + trueLabel, + valueRequired); + right.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + } else { + // x ^ + if ((bits & OnlyValueRequiredMASK) != 0) { + left.generateCode(currentScope, codeStream, valueRequired); + } else { + left.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + } + right.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + } + return; + } + } + // default case + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + codeStream.ixor(); + if ((bits & OnlyValueRequiredMASK) == 0) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicit falling through the FALSE case + codeStream.ifne(trueLabel); + } + } else { + // implicit falling through the TRUE case + if (trueLabel == null) { + codeStream.ifeq(falseLabel); + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + } + // reposition the endPC + codeStream.updateLastRecordedEndPC(codeStream.position); + } + + public void generateOptimizedStringBuffer( + BlockScope blockScope, + CodeStream codeStream, + int typeID) { + + /* In the case trying to make a string concatenation, there is no need to create a new + * string buffer, thus use a lower-level API for code generation involving only the + * appending of arguments to the existing StringBuffer + */ + + if ((((bits & OperatorMASK) >> OperatorSHIFT) == PLUS) + && ((bits & ReturnTypeIDMASK) == T_String)) { + if (constant != NotAConstant) { + codeStream.generateConstant(constant, implicitConversion); + codeStream.invokeStringBufferAppendForType(implicitConversion & 0xF); + } else { + int pc = codeStream.position; + left.generateOptimizedStringBuffer( + blockScope, + codeStream, + left.implicitConversion & 0xF); + codeStream.recordPositionsFrom(pc, left.sourceStart); + pc = codeStream.position; + right.generateOptimizedStringBuffer( + blockScope, + codeStream, + right.implicitConversion & 0xF); + codeStream.recordPositionsFrom(pc, right.sourceStart); + } + } else { + super.generateOptimizedStringBuffer(blockScope, codeStream, typeID); + } + } + + public void generateOptimizedStringBufferCreation( + BlockScope blockScope, + CodeStream codeStream, + int typeID) { + + /* In the case trying to make a string concatenation, there is no need to create a new + * string buffer, thus use a lower-level API for code generation involving only the + * appending of arguments to the existing StringBuffer + */ + + if ((((bits & OperatorMASK) >> OperatorSHIFT) == PLUS) + && ((bits & ReturnTypeIDMASK) == T_String)) { + if (constant != NotAConstant) { + codeStream.newStringBuffer(); // new: java.lang.StringBuffer + codeStream.dup(); + codeStream.ldc(constant.stringValue()); + codeStream.invokeStringBufferStringConstructor(); + // invokespecial: java.lang.StringBuffer.(Ljava.lang.String;)V + } else { + int pc = codeStream.position; + left.generateOptimizedStringBufferCreation( + blockScope, + codeStream, + left.implicitConversion & 0xF); + codeStream.recordPositionsFrom(pc, left.sourceStart); + pc = codeStream.position; + right.generateOptimizedStringBuffer( + blockScope, + codeStream, + right.implicitConversion & 0xF); + codeStream.recordPositionsFrom(pc, right.sourceStart); + } + } else { + super.generateOptimizedStringBufferCreation(blockScope, codeStream, typeID); + } + } + + public boolean isCompactableOperation() { + + return true; + } + + public void optimizedBooleanConstant(int leftId, int operator, int rightId) { + + switch (operator) { + case AND : + if ((leftId != T_boolean) || (rightId != T_boolean)) + return; + case AND_AND : + Constant cst; + if ((cst = left.optimizedBooleanConstant()) != NotAConstant) { + if (cst.booleanValue() == false) { // left is equivalent to false + optimizedBooleanConstant = cst; // constant(false) + return; + } else { //left is equivalent to true + if ((cst = right.optimizedBooleanConstant()) != NotAConstant) { + optimizedBooleanConstant = cst; + // the conditional result is equivalent to the right conditional value + } + return; + } + } + if ((cst = right.optimizedBooleanConstant()) != NotAConstant) { + if (cst.booleanValue() == false) { // right is equivalent to false + optimizedBooleanConstant = cst; // constant(false) + } + } + return; + case OR : + if ((leftId != T_boolean) || (rightId != T_boolean)) + return; + case OR_OR : + if ((cst = left.optimizedBooleanConstant()) != NotAConstant) { + if (cst.booleanValue() == true) { // left is equivalent to true + optimizedBooleanConstant = cst; // constant(true) + return; + } else { //left is equivalent to false + if ((cst = right.optimizedBooleanConstant()) != NotAConstant) { + optimizedBooleanConstant = cst; + } + return; + } + } + if ((cst = right.optimizedBooleanConstant()) != NotAConstant) { + if (cst.booleanValue() == true) { // right is equivalent to true + optimizedBooleanConstant = cst; // constant(true) + } + } + } + } + + public StringBuffer printExpressionNoParenthesis(int indent, StringBuffer output) { + + left.printExpression(indent, output).append(' ').append(operatorToString()).append(' '); + return right.printExpression(0, output); + } + + public TypeBinding resolveType(BlockScope scope) { + + boolean leftIsCast, rightIsCast; + if ((leftIsCast = left instanceof CastExpression) == true) left.bits |= IgnoreNeedForCastCheckMASK; // will check later on + TypeBinding leftType = left.resolveType(scope); + + if ((rightIsCast = right instanceof CastExpression) == true) right.bits |= IgnoreNeedForCastCheckMASK; // will check later on + TypeBinding rightType = right.resolveType(scope); + + // use the id of the type to navigate into the table + if (leftType == null || rightType == null) { + constant = Constant.NotAConstant; + return null; + } + int leftTypeId = leftType.id; + int rightTypeId = rightType.id; + if (leftTypeId > 15 + || rightTypeId > 15) { // must convert String + Object || Object + String + if (leftTypeId == T_String) { + rightTypeId = T_Object; + } else if (rightTypeId == T_String) { + leftTypeId = T_Object; + } else { + constant = Constant.NotAConstant; + scope.problemReporter().invalidOperator(this, leftType, rightType); + return null; + } + } + if (((bits & OperatorMASK) >> OperatorSHIFT) == PLUS) { + if (leftTypeId == T_String + && rightType.isArrayType() + && ((ArrayBinding) rightType).elementsType(scope) == CharBinding) { + scope.problemReporter().signalNoImplicitStringConversionForCharArrayExpression(right); + } else if (rightTypeId == T_String + && leftType.isArrayType() + && ((ArrayBinding) leftType).elementsType(scope) == CharBinding) { + scope.problemReporter().signalNoImplicitStringConversionForCharArrayExpression(left); + } + } + + // the code is an int + // (cast) left Op (cast) right --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 <<0 + + // Don't test for result = 0. If it is zero, some more work is done. + // On the one hand when it is not zero (correct code) we avoid doing the test + int operator = (bits & OperatorMASK) >> OperatorSHIFT; + int operatorSignature = OperatorSignatures[operator][(leftTypeId << 4) + rightTypeId]; + left.implicitConversion = operatorSignature >>> 12; + right.implicitConversion = (operatorSignature >>> 4) & 0x000FF; + + bits |= operatorSignature & 0xF; + switch (operatorSignature & 0xF) { // record the current ReturnTypeID + // only switch on possible result type..... + case T_boolean : + this.resolvedType = BooleanBinding; + break; + case T_byte : + this.resolvedType = ByteBinding; + break; + case T_char : + this.resolvedType = CharBinding; + break; + case T_double : + this.resolvedType = DoubleBinding; + break; + case T_float : + this.resolvedType = FloatBinding; + break; + case T_int : + this.resolvedType = IntBinding; + break; + case T_long : + this.resolvedType = LongBinding; + break; + case T_String : + this.resolvedType = scope.getJavaLangString(); + break; + default : //error........ + constant = Constant.NotAConstant; + scope.problemReporter().invalidOperator(this, leftType, rightType); + return null; + } + + // check need for operand cast + if (leftIsCast || rightIsCast) { + CastExpression.checkNeedForArgumentCasts(scope, operator, operatorSignature, left, leftTypeId, leftIsCast, right, rightTypeId, rightIsCast); + } + // compute the constant when valid + computeConstant(scope, leftTypeId, rightTypeId); + return this.resolvedType; + } + + public void traverse(ASTVisitor visitor, BlockScope scope) { + + if (visitor.visit(this, scope)) { + left.traverse(visitor, scope); + right.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/Block.java b/src/java/org/eclipse/jdt/internal/compiler/ast/Block.java new file mode 100644 index 0000000..f9170be --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/Block.java @@ -0,0 +1,142 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class Block extends Statement { + + public Statement[] statements; + public int explicitDeclarations; + // the number of explicit declaration , used to create scope + public BlockScope scope; + + public Block(int explicitDeclarations) { + this.explicitDeclarations = explicitDeclarations; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + // empty block + if (statements == null) return flowInfo; + boolean didAlreadyComplain = false; + for (int i = 0, max = statements.length; i < max; i++) { + Statement stat = statements[i]; + if (!stat.complainIfUnreachable(flowInfo, scope, didAlreadyComplain)) { + flowInfo = stat.analyseCode(scope, flowContext, flowInfo); + } else { + didAlreadyComplain = true; + } + } + return flowInfo; + } + /** + * Code generation for a block + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + + if ((bits & IsReachableMASK) == 0) { + return; + } + int pc = codeStream.position; + if (statements != null) { + for (int i = 0, max = statements.length; i < max; i++) { + statements[i].generateCode(scope, codeStream); + } + } // for local variable debug attributes + if (scope != currentScope) { // was really associated with its own scope + codeStream.exitUserScope(scope); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public boolean isEmptyBlock() { + + return statements == null; + } + + public StringBuffer printBody(int indent, StringBuffer output) { + + if (this.statements == null) return output; + for (int i = 0; i < statements.length; i++) { + statements[i].printStatement(indent + 1, output); + output.append('\n'); + } + return output; + } + + public StringBuffer printStatement(int indent, StringBuffer output) { + + printIndent(indent, output); + output.append("{\n"); //$NON-NLS-1$ + printBody(indent, output); + return printIndent(indent, output).append('}'); + } + + public void resolve(BlockScope upperScope) { + + if ((this.bits & UndocumentedEmptyBlockMASK) != 0) { + upperScope.problemReporter().undocumentedEmptyBlock(this.sourceStart, this.sourceEnd); + } + if (statements != null) { + scope = + explicitDeclarations == 0 + ? upperScope + : new BlockScope(upperScope, explicitDeclarations); + for (int i = 0, length = statements.length; i < length; i++) { + statements[i].resolve(scope); + } + } + } + + public void resolveUsing(BlockScope givenScope) { + + if ((this.bits & UndocumentedEmptyBlockMASK) != 0) { + givenScope.problemReporter().undocumentedEmptyBlock(this.sourceStart, this.sourceEnd); + } + // this optimized resolve(...) is sent only on none empty blocks + scope = givenScope; + if (statements != null) { + for (int i = 0, length = statements.length; i < length; i++) { + statements[i].resolve(scope); + } + } + } + + public void traverse( + ASTVisitor visitor, + BlockScope blockScope) { + + if (visitor.visit(this, blockScope)) { + if (statements != null) { + for (int i = 0, length = statements.length; i < length; i++) + statements[i].traverse(visitor, scope); + } + } + visitor.endVisit(this, blockScope); + } + + /** + * Dispatch the call on its last statement. + */ + public void branchChainTo(Label label) { + if (this.statements != null) { + this.statements[statements.length - 1].branchChainTo(label); + } + } + +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/BranchStatement.java b/src/java/org/eclipse/jdt/internal/compiler/ast/BranchStatement.java new file mode 100644 index 0000000..2dede48 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/BranchStatement.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public abstract class BranchStatement extends Statement { + public char[] label; + public Label targetLabel; + public SubRoutineStatement[] subroutines; +/** + * BranchStatement constructor comment. + */ +public BranchStatement(char[] l, int s,int e) { + label = l ; + sourceStart = s; + sourceEnd = e; +} +/** + * Branch code generation + * + * generate the finallyInvocationSequence. + */ +public void generateCode(BlockScope currentScope, CodeStream codeStream) { + + if ((bits & IsReachableMASK) == 0) { + return; + } + int pc = codeStream.position; + + // generation of code responsible for invoking the finally + // blocks in sequence + if (subroutines != null){ + for (int i = 0, max = subroutines.length; i < max; i++){ + SubRoutineStatement sub = subroutines[i]; + sub.generateSubRoutineInvocation(currentScope, codeStream); + if (sub.isSubRoutineEscaping()) { + codeStream.recordPositionsFrom(pc, this.sourceStart); + SubRoutineStatement.reenterExceptionHandlers(subroutines, i, codeStream); + return; + } + sub.exitAnyExceptionHandler(); + } + } + codeStream.goto_(targetLabel); + codeStream.recordPositionsFrom(pc, this.sourceStart); + SubRoutineStatement.reenterExceptionHandlers(subroutines, -1, codeStream); +} +public void resolve(BlockScope scope) { + // nothing to do during name resolution +} + +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/BreakStatement.java b/src/java/org/eclipse/jdt/internal/compiler/ast/BreakStatement.java new file mode 100644 index 0000000..dab79fe --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/BreakStatement.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class BreakStatement extends BranchStatement { + + public BreakStatement(char[] label, int sourceStart, int e) { + super(label, sourceStart, e); + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + // here requires to generate a sequence of finally blocks invocations depending corresponding + // to each of the traversed try statements, so that execution will terminate properly. + + // lookup the label, this should answer the returnContext + FlowContext targetContext = (label == null) + ? flowContext.getTargetContextForDefaultBreak() + : flowContext.getTargetContextForBreakLabel(label); + + if (targetContext == null) { + if (label == null) { + currentScope.problemReporter().invalidBreak(this); + } else { + currentScope.problemReporter().undefinedLabel(this); + } + return flowInfo; // pretend it did not break since no actual target + } + + targetLabel = targetContext.breakLabel(); + FlowContext traversedContext = flowContext; + int subIndex = 0, maxSub = 5; + subroutines = new SubRoutineStatement[maxSub]; + + do { + SubRoutineStatement sub; + if ((sub = traversedContext.subRoutine()) != null) { + if (subIndex == maxSub) { + System.arraycopy(subroutines, 0, (subroutines = new SubRoutineStatement[maxSub*=2]), 0, subIndex); // grow + } + subroutines[subIndex++] = sub; + if (sub.isSubRoutineEscaping()) { + break; + } + } + traversedContext.recordReturnFrom(flowInfo.unconditionalInits()); + + ASTNode node; + if ((node = traversedContext.associatedNode) instanceof TryStatement) { + TryStatement tryStatement = (TryStatement) node; + flowInfo.addInitializationsFrom(tryStatement.subRoutineInits); // collect inits + } else if (traversedContext == targetContext) { + // only record break info once accumulated through subroutines, and only against target context + targetContext.recordBreakFrom(flowInfo); + break; + } + } while ((traversedContext = traversedContext.parent) != null); + + // resize subroutines + if (subIndex != maxSub) { + System.arraycopy(subroutines, 0, (subroutines = new SubRoutineStatement[subIndex]), 0, subIndex); + } + return FlowInfo.DEAD_END; + } + + public StringBuffer printStatement(int tab, StringBuffer output) { + + printIndent(tab, output).append("break "); //$NON-NLS-1$ + if (label != null) output.append(label); + return output.append(';'); + } + + public void traverse( + ASTVisitor visitor, + BlockScope blockscope) { + + visitor.visit(this, blockscope); + visitor.endVisit(this, blockscope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java b/src/java/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java new file mode 100644 index 0000000..56380f7 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java @@ -0,0 +1,117 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class CaseStatement extends Statement { + + public Expression constantExpression; + public CaseLabel targetLabel; + public CaseStatement(Expression constantExpression, int sourceEnd, int sourceStart) { + this.constantExpression = constantExpression; + this.sourceEnd = sourceEnd; + this.sourceStart = sourceStart; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + if (constantExpression != null) { + if (constantExpression.constant == NotAConstant) { + currentScope.problemReporter().caseExpressionMustBeConstant(constantExpression); + } + this.constantExpression.analyseCode(currentScope, flowContext, flowInfo); + } + return flowInfo; + } + + public StringBuffer printStatement(int tab, StringBuffer output) { + + printIndent(tab, output); + if (constantExpression == null) { + output.append("default : "); //$NON-NLS-1$ + } else { + output.append("case "); //$NON-NLS-1$ + constantExpression.printExpression(0, output).append(" : "); //$NON-NLS-1$ + } + return output.append(';'); + } + + /** + * Case code generation + * + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + + if ((bits & IsReachableMASK) == 0) { + return; + } + int pc = codeStream.position; + targetLabel.place(); + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + /** + * No-op : should use resolveCase(...) instead. + */ + public void resolve(BlockScope scope) { + // no-op : should use resolveCase(...) instead. + } + + public Constant resolveCase( + BlockScope scope, + TypeBinding switchType, + SwitchStatement switchStatement) { + + scope.switchCase = this; // record entering in a switch case block + + if (constantExpression == null) { + // remember the default case into the associated switch statement + if (switchStatement.defaultCase != null) + scope.problemReporter().duplicateDefaultCase(this); + + // on error the last default will be the selected one ... + switchStatement.defaultCase = this; + return null; + } + // add into the collection of cases of the associated switch statement + switchStatement.cases[switchStatement.caseCount++] = this; + TypeBinding caseType = constantExpression.resolveType(scope); + if (caseType == null || switchType == null) return null; + if (constantExpression.isConstantValueOfTypeAssignableToType(caseType, switchType)) + return constantExpression.constant; + if (caseType.isCompatibleWith(switchType)) + return constantExpression.constant; + scope.problemReporter().typeMismatchErrorActualTypeExpectedType( + constantExpression, + caseType, + switchType); + return null; + } + + + public void traverse( + ASTVisitor visitor, + BlockScope blockScope) { + + if (visitor.visit(this, blockScope)) { + if (constantExpression != null) constantExpression.traverse(visitor, blockScope); + } + visitor.endVisit(this, blockScope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/CastExpression.java b/src/java/org/eclipse/jdt/internal/compiler/ast/CastExpression.java new file mode 100644 index 0000000..ecfe767 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/CastExpression.java @@ -0,0 +1,512 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Nick Teryaev - fix for bug (https://bugs.eclipse.org/bugs/show_bug.cgi?id=40752) + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; +import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; + +public class CastExpression extends Expression { + + public Expression expression; + public Expression type; + + //expression.implicitConversion holds the cast for baseType casting + public CastExpression(Expression expression, Expression type) { + this.expression = expression; + this.type = type; + + //due to the fact an expression may start with ( and that a cast also start with ( + //the field is an expression....it can be a TypeReference OR a NameReference Or + //an expression <--this last one is invalid....... + + //if (type instanceof TypeReference ) + // flag = IsTypeReference ; + //else + // if (type instanceof NameReference) + // flag = IsNameReference ; + // else + // flag = IsExpression ; + + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + return expression + .analyseCode(currentScope, flowContext, flowInfo) + .unconditionalInits(); + } + + /** + * Returns false if the cast is unnecessary + */ + public final boolean checkCastTypesCompatibility( + BlockScope scope, + TypeBinding castType, + TypeBinding expressionType) { + + // see specifications 5.5 + // handle errors and process constant when needed + + // if either one of the type is null ==> + // some error has been already reported some where ==> + // we then do not report an obvious-cascade-error. + + if (castType == null || expressionType == null) return true; + + // identity conversion cannot be performed upfront, due to side-effects + // like constant propagation + + if (castType.isBaseType()) { + if (expressionType.isBaseType()) { + if (expressionType == castType) { + expression.implicitWidening(castType, expressionType); + constant = expression.constant; //use the same constant + return false; + } + boolean necessary = false; + if (expressionType.isCompatibleWith(castType) + || (necessary = BaseTypeBinding.isNarrowing(castType.id, expressionType.id))) { + expression.implicitConversion = (castType.id << 4) + expressionType.id; + if (expression.constant != Constant.NotAConstant) { + constant = expression.constant.castTo(expression.implicitConversion); + } + return necessary; + + } + } + scope.problemReporter().typeCastError(this, castType, expressionType); + return true; + } + + //-----------cast to something which is NOT a base type-------------------------- + if (expressionType == NullBinding) { + // if (castType.isArrayType()){ // 26903 - need checkcast when casting null to array type + // needRuntimeCheckcast = true; + // } + return false; //null is compatible with every thing + } + if (expressionType.isBaseType()) { + scope.problemReporter().typeCastError(this, castType, expressionType); + return true; + } + + if (expressionType.isArrayType()) { + if (castType == expressionType) return false; // identity conversion + + if (castType.isArrayType()) { + //------- (castType.isArray) expressionType.isArray ----------- + TypeBinding exprElementType = ((ArrayBinding) expressionType).elementsType(scope); + if (exprElementType.isBaseType()) { + // <---stop the recursion------- + if (((ArrayBinding) castType).elementsType(scope) == exprElementType) { + this.bits |= NeedRuntimeCheckCastMASK; + } else { + scope.problemReporter().typeCastError(this, castType, expressionType); + } + return true; + } + // recursively on the elements... + return checkCastTypesCompatibility( + scope, + ((ArrayBinding) castType).elementsType(scope), + exprElementType); + } else if ( + castType.isClass()) { + //------(castType.isClass) expressionType.isArray --------------- + if (castType.id == T_Object) { + return false; + } + } else { //------- (castType.isInterface) expressionType.isArray ----------- + if (castType.id == T_JavaLangCloneable || castType.id == T_JavaIoSerializable) { + this.bits |= NeedRuntimeCheckCastMASK; + return true; + } + } + scope.problemReporter().typeCastError(this, castType, expressionType); + return true; + } + + if (expressionType.isClass()) { + if (castType.isArrayType()) { + // ---- (castType.isArray) expressionType.isClass ------- + if (expressionType.id == T_Object) { // potential runtime error + this.bits |= NeedRuntimeCheckCastMASK; + return true; + } + } else if (castType.isClass()) { // ----- (castType.isClass) expressionType.isClass ------ + if (expressionType.isCompatibleWith(castType)){ // no runtime error + if (castType.id == T_String) constant = expression.constant; // (String) cst is still a constant + return false; + } + if (castType.isCompatibleWith(expressionType)) { + // potential runtime error + this.bits |= NeedRuntimeCheckCastMASK; + return true; + } + } else { // ----- (castType.isInterface) expressionType.isClass ------- + if (expressionType.isCompatibleWith(castType)) + return false; + if (!((ReferenceBinding) expressionType).isFinal()) { + // a subclass may implement the interface ==> no check at compile time + this.bits |= NeedRuntimeCheckCastMASK; + return true; + } + // no subclass for expressionType, thus compile-time check is valid + } + scope.problemReporter().typeCastError(this, castType, expressionType); + return true; + } + + // if (expressionType.isInterface()) { cannot be anything else + if (castType.isArrayType()) { + // ----- (castType.isArray) expressionType.isInterface ------ + if (expressionType.id == T_JavaLangCloneable + || expressionType.id == T_JavaIoSerializable) {// potential runtime error + this.bits |= NeedRuntimeCheckCastMASK; + } else { + scope.problemReporter().typeCastError(this, castType, expressionType); + } + return true; + } else if (castType.isClass()) { // ----- (castType.isClass) expressionType.isInterface -------- + if (castType.id == T_Object) { // no runtime error + return false; + } + if (((ReferenceBinding) castType).isFinal()) { + // no subclass for castType, thus compile-time check is valid + if (!castType.isCompatibleWith(expressionType)) { + // potential runtime error + scope.problemReporter().typeCastError(this, castType, expressionType); + return true; + } + } + } else { // ----- (castType.isInterface) expressionType.isInterface ------- + if (expressionType.isCompatibleWith(castType)) { + return false; + } + if (!castType.isCompatibleWith(expressionType)) { + MethodBinding[] castTypeMethods = ((ReferenceBinding) castType).methods(); + MethodBinding[] expressionTypeMethods = + ((ReferenceBinding) expressionType).methods(); + int exprMethodsLength = expressionTypeMethods.length; + for (int i = 0, castMethodsLength = castTypeMethods.length; i < castMethodsLength; i++) + for (int j = 0; j < exprMethodsLength; j++) { + if ((castTypeMethods[i].returnType != expressionTypeMethods[j].returnType) + && (CharOperation.equals(castTypeMethods[i].selector, expressionTypeMethods[j].selector)) + && castTypeMethods[i].areParametersEqual(expressionTypeMethods[j])) { + scope.problemReporter().typeCastError(this, castType, expressionType); + } + } + } + } + this.bits |= NeedRuntimeCheckCastMASK; + return true; + } + + /** + * Casting an enclosing instance will considered as useful if removing it would actually bind to a different type + */ + public static void checkNeedForEnclosingInstanceCast(BlockScope scope, Expression enclosingInstance, TypeBinding enclosingInstanceType, TypeBinding memberType) { + + if (scope.environment().options.getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return; + + TypeBinding castedExpressionType = ((CastExpression)enclosingInstance).expression.resolvedType; + if (castedExpressionType == null) return; // cannot do better + // obvious identity cast + if (castedExpressionType == enclosingInstanceType) { + scope.problemReporter().unnecessaryCast((CastExpression)enclosingInstance); + } else if (castedExpressionType == NullBinding){ + return; // tolerate null enclosing instance cast + } else { + TypeBinding alternateEnclosingInstanceType = castedExpressionType; + if (castedExpressionType.isBaseType() || castedExpressionType.isArrayType()) return; // error case + if (memberType == scope.getMemberType(memberType.sourceName(), (ReferenceBinding) alternateEnclosingInstanceType)) { + scope.problemReporter().unnecessaryCast((CastExpression)enclosingInstance); + } + } + } + + /** + * Only complain for identity cast, since other type of casts may be useful: e.g. ~((~(long) 0) << 32) is different from: ~((~0) << 32) + */ + public static void checkNeedForArgumentCast(BlockScope scope, int operator, int operatorSignature, Expression expression, int expressionTypeId) { + + if (scope.environment().options.getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return; + + // check need for left operand cast + int alternateLeftTypeId = expressionTypeId; + if ((expression.bits & UnnecessaryCastMask) == 0 && expression.resolvedType.isBaseType()) { + // narrowing conversion on base type may change value, thus necessary + return; + } else { + TypeBinding alternateLeftType = ((CastExpression)expression).expression.resolvedType; + if (alternateLeftType == null) return; // cannot do better + if ((alternateLeftTypeId = alternateLeftType.id) == expressionTypeId) { // obvious identity cast + scope.problemReporter().unnecessaryCast((CastExpression)expression); + return; + } else if (alternateLeftTypeId == T_null) { + alternateLeftTypeId = expressionTypeId; // tolerate null argument cast + return; + } + } +/* tolerate widening cast in unary expressions, as may be used when combined in binary expressions (41680) + int alternateOperatorSignature = OperatorExpression.OperatorSignatures[operator][(alternateLeftTypeId << 4) + alternateLeftTypeId]; + // (cast) left Op (cast) right --> result + // 1111 0000 1111 0000 1111 + // <<16 <<12 <<8 <<4 <<0 + final int CompareMASK = (0xF<<16) + (0xF<<8) + 0xF; // mask hiding compile-time types + if ((operatorSignature & CompareMASK) == (alternateOperatorSignature & CompareMASK)) { // same promotions and result + scope.problemReporter().unnecessaryCastForArgument((CastExpression)expression, TypeBinding.wellKnownType(scope, expression.implicitConversion >> 4)); + } +*/ + } + + /** + * Cast expressions will considered as useful if removing them all would actually bind to a different method + * (no fine grain analysis on per casted argument basis, simply separate widening cast from narrowing ones) + */ + public static void checkNeedForArgumentCasts(BlockScope scope, Expression receiver, TypeBinding receiverType, MethodBinding binding, Expression[] arguments, TypeBinding[] argumentTypes, final InvocationSite invocationSite) { + + if (scope.environment().options.getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return; + + int length = argumentTypes.length; + + // iterate over arguments, and retrieve original argument types (before cast) + TypeBinding[] rawArgumentTypes = argumentTypes; + for (int i = 0; i < length; i++) { + Expression argument = arguments[i]; + if (argument instanceof CastExpression) { + // narrowing conversion on base type may change value, thus necessary + if ((argument.bits & UnnecessaryCastMask) == 0 && argument.resolvedType.isBaseType()) { + continue; + } + TypeBinding castedExpressionType = ((CastExpression)argument).expression.resolvedType; + if (castedExpressionType == null) return; // cannot do better + // obvious identity cast + if (castedExpressionType == argumentTypes[i]) { + scope.problemReporter().unnecessaryCast((CastExpression)argument); + } else if (castedExpressionType == NullBinding){ + continue; // tolerate null argument cast + } else { + if (rawArgumentTypes == argumentTypes) { + System.arraycopy(rawArgumentTypes, 0, rawArgumentTypes = new TypeBinding[length], 0, length); + } + // retain original argument type + rawArgumentTypes[i] = castedExpressionType; + } + } + } + // perform alternate lookup with original types + if (rawArgumentTypes != argumentTypes) { + checkAlternateBinding(scope, receiver, receiverType, binding, arguments, argumentTypes, rawArgumentTypes, invocationSite); + } + } + + /** + * Check binary operator casted arguments + */ + public static void checkNeedForArgumentCasts(BlockScope scope, int operator, int operatorSignature, Expression left, int leftTypeId, boolean leftIsCast, Expression right, int rightTypeId, boolean rightIsCast) { + + if (scope.environment().options.getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return; + + // check need for left operand cast + int alternateLeftTypeId = leftTypeId; + if (leftIsCast) { + if ((left.bits & UnnecessaryCastMask) == 0 && left.resolvedType.isBaseType()) { + // narrowing conversion on base type may change value, thus necessary + leftIsCast = false; + } else { + TypeBinding alternateLeftType = ((CastExpression)left).expression.resolvedType; + if (alternateLeftType == null) return; // cannot do better + if ((alternateLeftTypeId = alternateLeftType.id) == leftTypeId) { // obvious identity cast + scope.problemReporter().unnecessaryCast((CastExpression)left); + leftIsCast = false; + } else if (alternateLeftTypeId == T_null) { + alternateLeftTypeId = leftTypeId; // tolerate null argument cast + leftIsCast = false; + } + } + } + // check need for right operand cast + int alternateRightTypeId = rightTypeId; + if (rightIsCast) { + if ((right.bits & UnnecessaryCastMask) == 0 && right.resolvedType.isBaseType()) { + // narrowing conversion on base type may change value, thus necessary + rightIsCast = false; + } else { + TypeBinding alternateRightType = ((CastExpression)right).expression.resolvedType; + if (alternateRightType == null) return; // cannot do better + if ((alternateRightTypeId = alternateRightType.id) == rightTypeId) { // obvious identity cast + scope.problemReporter().unnecessaryCast((CastExpression)right); + rightIsCast = false; + } else if (alternateRightTypeId == T_null) { + alternateRightTypeId = rightTypeId; // tolerate null argument cast + rightIsCast = false; + } + } + } + if (leftIsCast || rightIsCast) { + if (alternateLeftTypeId > 15 || alternateRightTypeId > 15) { // must convert String + Object || Object + String + if (alternateLeftTypeId == T_String) { + alternateRightTypeId = T_Object; + } else if (alternateRightTypeId == T_String) { + alternateLeftTypeId = T_Object; + } else { + return; // invalid operator + } + } + int alternateOperatorSignature = OperatorExpression.OperatorSignatures[operator][(alternateLeftTypeId << 4) + alternateRightTypeId]; + // (cast) left Op (cast) right --> result + // 1111 0000 1111 0000 1111 + // <<16 <<12 <<8 <<4 <<0 + final int CompareMASK = (0xF<<16) + (0xF<<8) + 0xF; // mask hiding compile-time types + if ((operatorSignature & CompareMASK) == (alternateOperatorSignature & CompareMASK)) { // same promotions and result + if (leftIsCast) scope.problemReporter().unnecessaryCastForArgument((CastExpression)left, TypeBinding.wellKnownType(scope, left.implicitConversion >> 4)); + if (rightIsCast) scope.problemReporter().unnecessaryCastForArgument((CastExpression)right, TypeBinding.wellKnownType(scope, right.implicitConversion >> 4)); + } + } + } + + private static void checkAlternateBinding(BlockScope scope, Expression receiver, TypeBinding receiverType, MethodBinding binding, Expression[] arguments, TypeBinding[] originalArgumentTypes, TypeBinding[] alternateArgumentTypes, final InvocationSite invocationSite) { + + InvocationSite fakeInvocationSite = new InvocationSite(){ + public boolean isSuperAccess(){ return invocationSite.isSuperAccess(); } + public boolean isTypeAccess() { return invocationSite.isTypeAccess(); } + public void setActualReceiverType(ReferenceBinding actualReceiverType) { /* ignore */} + public void setDepth(int depth) { /* ignore */} + public void setFieldIndex(int depth){ /* ignore */} + public int sourceStart() { return 0; } + public int sourceEnd() { return 0; } + }; + MethodBinding bindingIfNoCast; + if (binding.isConstructor()) { + bindingIfNoCast = scope.getConstructor((ReferenceBinding)receiverType, alternateArgumentTypes, fakeInvocationSite); + } else { + bindingIfNoCast = receiver.isImplicitThis() + ? scope.getImplicitMethod(binding.selector, alternateArgumentTypes, fakeInvocationSite) + : scope.getMethod(receiverType, binding.selector, alternateArgumentTypes, fakeInvocationSite); + } + if (bindingIfNoCast == binding) { + for (int i = 0, length = originalArgumentTypes.length; i < length; i++) { + if (originalArgumentTypes[i] != alternateArgumentTypes[i]) { + scope.problemReporter().unnecessaryCastForArgument((CastExpression)arguments[i], binding.parameters[i]); + } + } + } + } + /** + * Cast expression code generation + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ + public void generateCode( + BlockScope currentScope, + CodeStream codeStream, + boolean valueRequired) { + + int pc = codeStream.position; + boolean needRuntimeCheckcast = (this.bits & NeedRuntimeCheckCastMASK) != 0; + if (constant != NotAConstant) { + if (valueRequired || needRuntimeCheckcast) { // Added for: 1F1W9IG: IVJCOM:WINNT - Compiler omits casting check + codeStream.generateConstant(constant, implicitConversion); + if (needRuntimeCheckcast) { + codeStream.checkcast(this.resolvedType); + if (!valueRequired) + codeStream.pop(); + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + expression.generateCode( + currentScope, + codeStream, + valueRequired || needRuntimeCheckcast); + if (needRuntimeCheckcast) { + codeStream.checkcast(this.resolvedType); + if (!valueRequired) + codeStream.pop(); + } else { + if (valueRequired) + codeStream.generateImplicitConversion(implicitConversion); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public Expression innermostCastedExpression(){ + Expression current = this.expression; + while (current instanceof CastExpression) { + current = ((CastExpression) current).expression; + } + return current; + } + + public StringBuffer printExpression(int indent, StringBuffer output) { + + output.append('('); + type.print(0, output).append(") "); //$NON-NLS-1$ + return expression.printExpression(0, output); + } + + public TypeBinding resolveType(BlockScope scope) { + // compute a new constant if the cast is effective + + // due to the fact an expression may start with ( and that a cast can also start with ( + // the field is an expression....it can be a TypeReference OR a NameReference Or + // any kind of Expression <-- this last one is invalid....... + + constant = Constant.NotAConstant; + implicitConversion = T_undefined; + + if ((type instanceof TypeReference) || (type instanceof NameReference) + && ((type.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT) == 0) { // no extra parenthesis around type: ((A))exp + + this.resolvedType = type.resolveType(scope); + TypeBinding expressionType = expression.resolveType(scope); + if (this.resolvedType != null && expressionType != null) { + boolean necessary = checkCastTypesCompatibility(scope, this.resolvedType, expressionType); + if (!necessary && this.expression.resolvedType != null) { // cannot do better if expression is not bound + this.bits |= UnnecessaryCastMask; + if ((this.bits & IgnoreNeedForCastCheckMASK) == 0) { + scope.problemReporter().unnecessaryCast(this); + } + } + } + return this.resolvedType; + } else { // expression as a cast !!!!!!!! + TypeBinding expressionType = expression.resolveType(scope); + if (expressionType == null) return null; + scope.problemReporter().invalidTypeReference(type); + return null; + } + } + + public void traverse( + ASTVisitor visitor, + BlockScope blockScope) { + + if (visitor.visit(this, blockScope)) { + type.traverse(visitor, blockScope); + expression.traverse(visitor, blockScope); + } + visitor.endVisit(this, blockScope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/CharLiteral.java b/src/java/org/eclipse/jdt/internal/compiler/ast/CharLiteral.java new file mode 100644 index 0000000..c2d90b0 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/CharLiteral.java @@ -0,0 +1,101 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class CharLiteral extends NumberLiteral { + char value; +public CharLiteral(char[] token, int s, int e) { + super(token, s, e); + computeValue(); +} +public void computeConstant() { + //The source is a char[3] first and last char are ' + //This is true for both regular char AND unicode char + //BUT not for escape char like '\b' which are char[4].... + + constant = Constant.fromValue(value); +} +private void computeValue() { + //The source is a char[3] first and last char are ' + //This is true for both regular char AND unicode char + //BUT not for escape char like '\b' which are char[4].... + + if ((value = source[1]) != '\\') + return; + char digit; + switch (digit = source[2]) { + case 'b' : + value = '\b'; + break; + case 't' : + value = '\t'; + break; + case 'n' : + value = '\n'; + break; + case 'f' : + value = '\f'; + break; + case 'r' : + value = '\r'; + break; + case '\"' : + value = '\"'; + break; + case '\'' : + value = '\''; + break; + case '\\' : + value = '\\'; + break; + default : //octal (well-formed: ended by a ' ) + int number = Character.getNumericValue(digit); + if ((digit = source[3]) != '\'') + number = (number * 8) + Character.getNumericValue(digit); + else { + constant = Constant.fromValue(value = (char) number); + break; + } + if ((digit = source[4]) != '\'') + number = (number * 8) + Character.getNumericValue(digit); + value = (char) number; + break; + } +} +/** + * CharLiteral code generation + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ +public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { + int pc = codeStream.position; + if (valueRequired) + if ((implicitConversion >> 4) == T_char) + codeStream.generateInlinedValue(value); + else + codeStream.generateConstant(constant, implicitConversion); + codeStream.recordPositionsFrom(pc, this.sourceStart); +} +public TypeBinding literalType(BlockScope scope) { + return CharBinding; +} +public void traverse(ASTVisitor visitor, BlockScope blockScope) { + visitor.visit(this, blockScope); + visitor.endVisit(this, blockScope); +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/ClassLiteralAccess.java b/src/java/org/eclipse/jdt/internal/compiler/ast/ClassLiteralAccess.java new file mode 100644 index 0000000..4a4136e --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/ClassLiteralAccess.java @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class ClassLiteralAccess extends Expression { + + public TypeReference type; + public TypeBinding targetType; + FieldBinding syntheticField; + + public ClassLiteralAccess(int sourceEnd, TypeReference t) { + type = t; + this.sourceStart = t.sourceStart; + this.sourceEnd = sourceEnd; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + // if reachable, request the addition of a synthetic field for caching the class descriptor + SourceTypeBinding sourceType = + currentScope.outerMostMethodScope().enclosingSourceType(); + if (!(sourceType.isInterface() + // no field generated in interface case (would'nt verify) see 1FHHEZL + || sourceType.isBaseType())) { + syntheticField = sourceType.addSyntheticField(targetType, currentScope); + } + return flowInfo; + } + + /** + * MessageSendDotClass code generation + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ + public void generateCode( + BlockScope currentScope, + CodeStream codeStream, + boolean valueRequired) { + int pc = codeStream.position; + + // in interface case, no caching occurs, since cannot make a cache field for interface + if (valueRequired) + codeStream.generateClassLiteralAccessForType(type.resolvedType, syntheticField); + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public StringBuffer printExpression(int indent, StringBuffer output) { + + return type.print(0, output).append(".class"); //$NON-NLS-1$ + } + + public TypeBinding resolveType(BlockScope scope) { + + constant = NotAConstant; + if ((targetType = type.resolveType(scope)) == null) + return null; + + if (targetType.isArrayType() + && ((ArrayBinding) targetType).leafComponentType == VoidBinding) { + scope.problemReporter().cannotAllocateVoidArray(this); + return null; + } + + return this.resolvedType = scope.getJavaLangClass(); + } + + public void traverse( + ASTVisitor visitor, + BlockScope blockScope) { + + if (visitor.visit(this, blockScope)) { + type.traverse(visitor, blockScope); + } + visitor.endVisit(this, blockScope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/Clinit.java b/src/java/org/eclipse/jdt/internal/compiler/ast/Clinit.java new file mode 100644 index 0000000..2bbac9c --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/Clinit.java @@ -0,0 +1,246 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.*; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; +import org.eclipse.jdt.internal.compiler.parser.*; +import org.eclipse.jdt.internal.compiler.problem.*; + +public class Clinit extends AbstractMethodDeclaration { + + public final static char[] ConstantPoolName = "".toCharArray(); //$NON-NLS-1$ + + private FieldBinding assertionSyntheticFieldBinding = null; + private FieldBinding classLiteralSyntheticField = null; + + public Clinit(CompilationResult compilationResult) { + super(compilationResult); + modifiers = 0; + selector = ConstantPoolName; + } + + public void analyseCode( + ClassScope classScope, + InitializationFlowContext staticInitializerFlowContext, + FlowInfo flowInfo) { + + if (ignoreFurtherInvestigation) + return; + try { + ExceptionHandlingFlowContext clinitContext = + new ExceptionHandlingFlowContext( + staticInitializerFlowContext.parent, + this, + NoExceptions, + scope, + FlowInfo.DEAD_END); + + // check for missing returning path + this.needFreeReturn = flowInfo.isReachable(); + + // check missing blank final field initializations + flowInfo = flowInfo.mergedWith(staticInitializerFlowContext.initsOnReturn); + FieldBinding[] fields = scope.enclosingSourceType().fields(); + for (int i = 0, count = fields.length; i < count; i++) { + FieldBinding field; + if ((field = fields[i]).isStatic() + && field.isFinal() + && (!flowInfo.isDefinitelyAssigned(fields[i]))) { + scope.problemReporter().uninitializedBlankFinalField( + field, + scope.referenceType().declarationOf(field)); + // can complain against the field decl, since only one + } + } + // check static initializers thrown exceptions + staticInitializerFlowContext.checkInitializerExceptions( + scope, + clinitContext, + flowInfo); + } catch (AbortMethod e) { + this.ignoreFurtherInvestigation = true; + } + } + + /** + * Bytecode generation for a method + * + * @param classScope org.eclipse.jdt.internal.compiler.lookup.ClassScope + * @param classFile org.eclipse.jdt.internal.compiler.codegen.ClassFile + */ + public void generateCode(ClassScope classScope, ClassFile classFile) { + + int clinitOffset = 0; + if (ignoreFurtherInvestigation) { + // should never have to add any problem method + return; + } + try { + clinitOffset = classFile.contentsOffset; + this.generateCode(classScope, classFile, clinitOffset); + } catch (AbortMethod e) { + // should never occur + // the clinit referenceContext is the type declaration + // All clinit problems will be reported against the type: AbortType instead of AbortMethod + // reset the contentsOffset to the value before generating the clinit code + // decrement the number of method info as well. + // This is done in the addProblemMethod and addProblemConstructor for other + // cases. + if (e.compilationResult == CodeStream.RESTART_IN_WIDE_MODE) { + // a branch target required a goto_w, restart code gen in wide mode. + try { + classFile.contentsOffset = clinitOffset; + classFile.methodCount--; + classFile.codeStream.wideMode = true; // request wide mode + this.generateCode(classScope, classFile, clinitOffset); + // restart method generation + } catch (AbortMethod e2) { + classFile.contentsOffset = clinitOffset; + classFile.methodCount--; + } + } else { + // produce a problem method accounting for this fatal error + classFile.contentsOffset = clinitOffset; + classFile.methodCount--; + } + } + } + + /** + * Bytecode generation for a method + * + * @param classScope org.eclipse.jdt.internal.compiler.lookup.ClassScope + * @param classFile org.eclipse.jdt.internal.compiler.codegen.ClassFile + */ + private void generateCode( + ClassScope classScope, + ClassFile classFile, + int clinitOffset) { + + ConstantPool constantPool = classFile.constantPool; + int constantPoolOffset = constantPool.currentOffset; + int constantPoolIndex = constantPool.currentIndex; + classFile.generateMethodInfoHeaderForClinit(); + int codeAttributeOffset = classFile.contentsOffset; + classFile.generateCodeAttributeHeader(); + CodeStream codeStream = classFile.codeStream; + this.resolve(classScope); + + codeStream.reset(this, classFile); + TypeDeclaration declaringType = classScope.referenceContext; + + // initialize local positions - including initializer scope. + MethodScope staticInitializerScope = declaringType.staticInitializerScope; + staticInitializerScope.computeLocalVariablePositions(0, codeStream); + + // 1.4 feature + // This has to be done before any other initialization + if (this.assertionSyntheticFieldBinding != null) { + // generate code related to the activation of assertion for this class + codeStream.generateClassLiteralAccessForType( + classScope.enclosingSourceType(), + classLiteralSyntheticField); + codeStream.invokeJavaLangClassDesiredAssertionStatus(); + Label falseLabel = new Label(codeStream); + codeStream.ifne(falseLabel); + codeStream.iconst_1(); + Label jumpLabel = new Label(codeStream); + codeStream.goto_(jumpLabel); + falseLabel.place(); + codeStream.iconst_0(); + jumpLabel.place(); + codeStream.putstatic(this.assertionSyntheticFieldBinding); + } + // generate initializers + if (declaringType.fields != null) { + for (int i = 0, max = declaringType.fields.length; i < max; i++) { + FieldDeclaration fieldDecl; + if ((fieldDecl = declaringType.fields[i]).isStatic()) { + fieldDecl.generateCode(staticInitializerScope, codeStream); + } + } + } + if (codeStream.position == 0) { + // do not need to output a Clinit if no bytecodes + // so we reset the offset inside the byte array contents. + classFile.contentsOffset = clinitOffset; + // like we don't addd a method we need to undo the increment on the method count + classFile.methodCount--; + // reset the constant pool to its state before the clinit + constantPool.resetForClinit(constantPoolIndex, constantPoolOffset); + } else { + if (this.needFreeReturn) { + int oldPosition = codeStream.position; + codeStream.return_(); + codeStream.updateLocalVariablesAttribute(oldPosition); + } + // Record the end of the clinit: point to the declaration of the class + codeStream.recordPositionsFrom(0, declaringType.sourceStart); + classFile.completeCodeAttributeForClinit(codeAttributeOffset); + } + } + + public boolean isClinit() { + + return true; + } + + public boolean isInitializationMethod() { + + return true; + } + + public boolean isStatic() { + + return true; + } + + public void parseStatements(Parser parser, CompilationUnitDeclaration unit) { + //the clinit is filled by hand .... + } + + public StringBuffer print(int tab, StringBuffer output) { + + printIndent(tab, output).append("()"); //$NON-NLS-1$ + printBody(tab + 1, output); + return output; + } + + public void resolve(ClassScope classScope) { + + this.scope = new MethodScope(classScope, classScope.referenceContext, true); + } + + public void traverse( + ASTVisitor visitor, + ClassScope classScope) { + + visitor.visit(this, classScope); + visitor.endVisit(this, classScope); + } + + // 1.4 feature + public void setAssertionSupport(FieldBinding assertionSyntheticFieldBinding) { + + this.assertionSyntheticFieldBinding = assertionSyntheticFieldBinding; + + // we need to add the field right now, because the field infos are generated before the methods + SourceTypeBinding sourceType = + this.scope.outerMostMethodScope().enclosingSourceType(); + this.classLiteralSyntheticField = + sourceType.addSyntheticField(sourceType, scope); + } + +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/CompilationUnitDeclaration.java b/src/java/org/eclipse/jdt/internal/compiler/ast/CompilationUnitDeclaration.java new file mode 100644 index 0000000..d736614 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/CompilationUnitDeclaration.java @@ -0,0 +1,316 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.core.compiler.*; +import org.eclipse.jdt.internal.compiler.*; +import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.lookup.*; +import org.eclipse.jdt.internal.compiler.problem.*; + +public class CompilationUnitDeclaration + extends ASTNode + implements ProblemSeverities, ReferenceContext { + + public ImportReference currentPackage; + public ImportReference[] imports; + public TypeDeclaration[] types; + public int[][] comments; + + public boolean ignoreFurtherInvestigation = false; // once pointless to investigate due to errors + public boolean ignoreMethodBodies = false; + public CompilationUnitScope scope; + public ProblemReporter problemReporter; + public CompilationResult compilationResult; + + public LocalTypeBinding[] localTypes; + public int localTypeCount = 0; + + public boolean isPropagatingInnerClassEmulation; + + public CompilationUnitDeclaration( + ProblemReporter problemReporter, + CompilationResult compilationResult, + int sourceLength) { + + this.problemReporter = problemReporter; + this.compilationResult = compilationResult; + + //by definition of a compilation unit.... + sourceStart = 0; + sourceEnd = sourceLength - 1; + + } + + /* + * We cause the compilation task to abort to a given extent. + */ + public void abort(int abortLevel, IProblem problem) { + + switch (abortLevel) { + case AbortType : + throw new AbortType(this.compilationResult, problem); + case AbortMethod : + throw new AbortMethod(this.compilationResult, problem); + default : + throw new AbortCompilationUnit(this.compilationResult, problem); + } + } + + /* + * Dispatch code analysis AND request saturation of inner emulation + */ + public void analyseCode() { + + if (ignoreFurtherInvestigation) + return; + try { + if (types != null) { + for (int i = 0, count = types.length; i < count; i++) { + types[i].analyseCode(scope); + } + } + // request inner emulation propagation + propagateInnerEmulationForAllLocalTypes(); + } catch (AbortCompilationUnit e) { + this.ignoreFurtherInvestigation = true; + return; + } + } + + /* + * When unit result is about to be accepted, removed back pointers + * to compiler structures. + */ + public void cleanUp() { + if (this.types != null) { + for (int i = 0, max = this.types.length; i < max; i++) { + cleanUp(this.types[i]); + } + for (int i = 0, max = this.localTypeCount; i < max; i++) { + LocalTypeBinding localType = localTypes[i]; + // null out the type's scope backpointers + localType.scope = null; // local members are already in the list + } + } + ClassFile[] classFiles = compilationResult.getClassFiles(); + for (int i = 0, max = classFiles.length; i < max; i++) { + // clear the classFile back pointer to the bindings + ClassFile classFile = classFiles[i]; + // null out the classfile backpointer to a type binding + classFile.referenceBinding = null; + classFile.codeStream = null; // codeStream holds onto ast and scopes + classFile.innerClassesBindings = null; + } + } + private void cleanUp(TypeDeclaration type) { + if (type.memberTypes != null) { + for (int i = 0, max = type.memberTypes.length; i < max; i++){ + cleanUp(type.memberTypes[i]); + } + } + if (type.binding != null) { + // null out the type's scope backpointers + type.binding.scope = null; + } + } + + public void checkUnusedImports(){ + + if (this.scope.imports != null){ + for (int i = 0, max = this.scope.imports.length; i < max; i++){ + ImportBinding importBinding = this.scope.imports[i]; + ImportReference importReference = importBinding.reference; + if (importReference != null && !importReference.used){ + scope.problemReporter().unusedImport(importReference); + } + } + } + } + + public CompilationResult compilationResult() { + return compilationResult; + } + + /* + * Finds the matching type amoung this compilation unit types. + * Returns null if no type with this name is found. + * The type name is a compound name + * eg. if we're looking for X.A.B then a type name would be {X, A, B} + */ + public TypeDeclaration declarationOfType(char[][] typeName) { + + for (int i = 0; i < this.types.length; i++) { + TypeDeclaration typeDecl = this.types[i].declarationOfType(typeName); + if (typeDecl != null) { + return typeDecl; + } + } + return null; + } + + /** + * Bytecode generation + */ + public void generateCode() { + + if (ignoreFurtherInvestigation) { + if (types != null) { + for (int i = 0, count = types.length; i < count; i++) { + types[i].ignoreFurtherInvestigation = true; + // propagate the flag to request problem type creation + types[i].generateCode(scope); + } + } + return; + } + try { + if (types != null) { + for (int i = 0, count = types.length; i < count; i++) + types[i].generateCode(scope); + } + } catch (AbortCompilationUnit e) { + // ignore + } + } + + public char[] getFileName() { + + return compilationResult.getFileName(); + } + + public char[] getMainTypeName() { + + if (compilationResult.compilationUnit == null) { + char[] fileName = compilationResult.getFileName(); + + int start = CharOperation.lastIndexOf('/', fileName) + 1; + if (start == 0 || start < CharOperation.lastIndexOf('\\', fileName)) + start = CharOperation.lastIndexOf('\\', fileName) + 1; + + int end = CharOperation.lastIndexOf('.', fileName); + if (end == -1) + end = fileName.length; + + return CharOperation.subarray(fileName, start, end); + } else { + return compilationResult.compilationUnit.getMainTypeName(); + } + } + + public boolean isEmpty() { + + return (currentPackage == null) && (imports == null) && (types == null); + } + + public boolean hasErrors() { + return this.ignoreFurtherInvestigation; + } + + public StringBuffer print(int indent, StringBuffer output) { + + if (currentPackage != null) { + printIndent(indent, output).append("package "); //$NON-NLS-1$ + currentPackage.print(0, output, false).append(";\n"); //$NON-NLS-1$ + } + if (imports != null) + for (int i = 0; i < imports.length; i++) { + printIndent(indent, output).append("import "); //$NON-NLS-1$ + imports[i].print(0, output).append(";\n"); //$NON-NLS-1$ + } + + if (types != null) { + for (int i = 0; i < types.length; i++) { + types[i].print(indent, output).append("\n"); //$NON-NLS-1$ + } + } + return output; + } + + /* + * Force inner local types to update their innerclass emulation + */ + public void propagateInnerEmulationForAllLocalTypes() { + + isPropagatingInnerClassEmulation = true; + for (int i = 0, max = this.localTypeCount; i < max; i++) { + + LocalTypeBinding localType = localTypes[i]; + // only propagate for reachable local types + if ((localType.scope.referenceType().bits & IsReachableMASK) != 0) { + localType.updateInnerEmulationDependents(); + } + } + } + + /* + * Keep track of all local types, so as to update their innerclass + * emulation later on. + */ + public void record(LocalTypeBinding localType) { + + if (this.localTypeCount == 0) { + this.localTypes = new LocalTypeBinding[5]; + } else if (this.localTypeCount == this.localTypes.length) { + System.arraycopy(this.localTypes, 0, (this.localTypes = new LocalTypeBinding[this.localTypeCount * 2]), 0, this.localTypeCount); + } + this.localTypes[this.localTypeCount++] = localType; + } + + public void resolve() { + + try { + if (types != null) { + for (int i = 0, count = types.length; i < count; i++) { + types[i].resolve(scope); + } + } + if (!this.compilationResult.hasSyntaxError()) checkUnusedImports(); + } catch (AbortCompilationUnit e) { + this.ignoreFurtherInvestigation = true; + return; + } + } + + public void tagAsHavingErrors() { + ignoreFurtherInvestigation = true; + } + + public void traverse( + ASTVisitor visitor, + CompilationUnitScope unitScope) { + + if (ignoreFurtherInvestigation) + return; + try { + if (visitor.visit(this, this.scope)) { + if (currentPackage != null) { + currentPackage.traverse(visitor, this.scope); + } + if (imports != null) { + int importLength = imports.length; + for (int i = 0; i < importLength; i++) { + imports[i].traverse(visitor, this.scope); + } + } + if (types != null) { + int typesLength = types.length; + for (int i = 0; i < typesLength; i++) { + types[i].traverse(visitor, this.scope); + } + } + } + visitor.endVisit(this, this.scope); + } catch (AbortCompilationUnit e) { + // ignore + } + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/CompoundAssignment.java b/src/java/org/eclipse/jdt/internal/compiler/ast/CompoundAssignment.java new file mode 100644 index 0000000..47745f1 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/CompoundAssignment.java @@ -0,0 +1,157 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class CompoundAssignment extends Assignment implements OperatorIds { + public int operator; + public int assignmentImplicitConversion; + + // var op exp is equivalent to var = (varType) var op exp + // assignmentImplicitConversion stores the cast needed for the assignment + + public CompoundAssignment(Expression lhs, Expression expression,int operator, int sourceEnd) { + //lhs is always a reference by construction , + //but is build as an expression ==> the checkcast cannot fail + + super(lhs, expression, sourceEnd); + lhs.bits &= ~IsStrictlyAssignedMASK; // tag lhs as NON assigned - it is also a read access + lhs.bits |= IsCompoundAssignedMASK; // tag lhs as assigned by compound + this.operator = operator ; + } + + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + // record setting a variable: various scenarii are possible, setting an array reference, + // a field reference, a blank final field reference, a field of an enclosing instance or + // just a local variable. + + return ((Reference) lhs).analyseAssignment(currentScope, flowContext, flowInfo, this, true).unconditionalInits(); + } + + public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { + + // various scenarii are possible, setting an array reference, + // a field reference, a blank final field reference, a field of an enclosing instance or + // just a local variable. + + int pc = codeStream.position; + ((Reference) lhs).generateCompoundAssignment(currentScope, codeStream, expression, operator, assignmentImplicitConversion, valueRequired); + if (valueRequired) { + codeStream.generateImplicitConversion(implicitConversion); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public String operatorToString() { + switch (operator) { + case PLUS : + return "+="; //$NON-NLS-1$ + case MINUS : + return "-="; //$NON-NLS-1$ + case MULTIPLY : + return "*="; //$NON-NLS-1$ + case DIVIDE : + return "/="; //$NON-NLS-1$ + case AND : + return "&="; //$NON-NLS-1$ + case OR : + return "|="; //$NON-NLS-1$ + case XOR : + return "^="; //$NON-NLS-1$ + case REMAINDER : + return "%="; //$NON-NLS-1$ + case LEFT_SHIFT : + return "<<="; //$NON-NLS-1$ + case RIGHT_SHIFT : + return ">>="; //$NON-NLS-1$ + case UNSIGNED_RIGHT_SHIFT : + return ">>>="; //$NON-NLS-1$ + } + return "unknown operator"; //$NON-NLS-1$ + } + + public StringBuffer printExpressionNoParenthesis(int indent, StringBuffer output) { + + lhs.printExpression(indent, output).append(' ').append(operatorToString()).append(' '); + return expression.printExpression(0, output) ; + } + + public TypeBinding resolveType(BlockScope scope) { + constant = NotAConstant; + if (!(this.lhs instanceof Reference) || this.lhs.isThis()) { + scope.problemReporter().expressionShouldBeAVariable(this.lhs); + return null; + } + TypeBinding lhsType = lhs.resolveType(scope); + TypeBinding expressionType = expression.resolveType(scope); + if (lhsType == null || expressionType == null) + return null; + + int lhsId = lhsType.id; + int expressionId = expressionType.id; + if (restrainUsageToNumericTypes() && !lhsType.isNumericType()) { + scope.problemReporter().operatorOnlyValidOnNumericType(this, lhsType, expressionType); + return null; + } + if (lhsId > 15 || expressionId > 15) { + if (lhsId != T_String) { // String += Thread is valid whereas Thread += String is not + scope.problemReporter().invalidOperator(this, lhsType, expressionType); + return null; + } + expressionId = T_Object; // use the Object has tag table + } + + // the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 <<0 + + // the conversion is stored INTO the reference (info needed for the code gen) + int result = OperatorExpression.OperatorSignatures[operator][ (lhsId << 4) + expressionId]; + if (result == T_undefined) { + scope.problemReporter().invalidOperator(this, lhsType, expressionType); + return null; + } + if (operator == PLUS){ + if(lhsId == T_JavaLangObject) { + // += is illegal (39248) + scope.problemReporter().invalidOperator(this, lhsType, expressionType); + return null; + } else { + // += is illegal + if ((lhsType.isNumericType() || lhsId == T_boolean) && !expressionType.isNumericType()){ + scope.problemReporter().invalidOperator(this, lhsType, expressionType); + return null; + } + } + } + lhs.implicitConversion = result >>> 12; + expression.implicitConversion = (result >>> 4) & 0x000FF; + assignmentImplicitConversion = (lhsId << 4) + (result & 0x0000F); + return this.resolvedType = lhsType; + } + + public boolean restrainUsageToNumericTypes(){ + return false ; + } + + public void traverse(ASTVisitor visitor, BlockScope scope) { + if (visitor.visit(this, scope)) { + lhs.traverse(visitor, scope); + expression.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java b/src/java/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java new file mode 100644 index 0000000..cf86373 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java @@ -0,0 +1,411 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class ConditionalExpression extends OperatorExpression { + + public Expression condition, valueIfTrue, valueIfFalse; + public Constant optimizedBooleanConstant; + public Constant optimizedIfTrueConstant; + public Constant optimizedIfFalseConstant; + + // for local variables table attributes + int trueInitStateIndex = -1; + int falseInitStateIndex = -1; + int mergedInitStateIndex = -1; + + public ConditionalExpression( + Expression condition, + Expression valueIfTrue, + Expression valueIfFalse) { + this.condition = condition; + this.valueIfTrue = valueIfTrue; + this.valueIfFalse = valueIfFalse; + sourceStart = condition.sourceStart; + sourceEnd = valueIfFalse.sourceEnd; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + Constant cst = this.condition.optimizedBooleanConstant(); + boolean isConditionOptimizedTrue = cst != NotAConstant && cst.booleanValue() == true; + boolean isConditionOptimizedFalse = cst != NotAConstant && cst.booleanValue() == false; + + int mode = flowInfo.reachMode(); + flowInfo = condition.analyseCode(currentScope, flowContext, flowInfo, cst == NotAConstant); + + // process the if-true part + FlowInfo trueFlowInfo = flowInfo.initsWhenTrue().copy(); + if (isConditionOptimizedFalse) { + trueFlowInfo.setReachMode(FlowInfo.UNREACHABLE); + } + trueInitStateIndex = currentScope.methodScope().recordInitializationStates(trueFlowInfo); + trueFlowInfo = valueIfTrue.analyseCode(currentScope, flowContext, trueFlowInfo); + + // process the if-false part + FlowInfo falseFlowInfo = flowInfo.initsWhenFalse().copy(); + if (isConditionOptimizedTrue) { + falseFlowInfo.setReachMode(FlowInfo.UNREACHABLE); + } + falseInitStateIndex = currentScope.methodScope().recordInitializationStates(falseFlowInfo); + falseFlowInfo = valueIfFalse.analyseCode(currentScope, flowContext, falseFlowInfo); + + // merge if-true & if-false initializations + FlowInfo mergedInfo; + if (isConditionOptimizedTrue){ + mergedInfo = trueFlowInfo.addPotentialInitializationsFrom(falseFlowInfo); + } else if (isConditionOptimizedFalse) { + mergedInfo = falseFlowInfo.addPotentialInitializationsFrom(trueFlowInfo); + } else { + // if ((t && (v = t)) ? t : t && (v = f)) r = v; -- ok + cst = this.optimizedIfTrueConstant; + boolean isValueIfTrueOptimizedTrue = cst != null && cst != NotAConstant && cst.booleanValue() == true; + boolean isValueIfTrueOptimizedFalse = cst != null && cst != NotAConstant && cst.booleanValue() == false; + + cst = this.optimizedIfFalseConstant; + boolean isValueIfFalseOptimizedTrue = cst != null && cst != NotAConstant && cst.booleanValue() == true; + boolean isValueIfFalseOptimizedFalse = cst != null && cst != NotAConstant && cst.booleanValue() == false; + + UnconditionalFlowInfo trueInfoWhenTrue = trueFlowInfo.initsWhenTrue().copy().unconditionalInits(); + if (isValueIfTrueOptimizedFalse) trueInfoWhenTrue.setReachMode(FlowInfo.UNREACHABLE); + + UnconditionalFlowInfo falseInfoWhenTrue = falseFlowInfo.initsWhenTrue().copy().unconditionalInits(); + if (isValueIfFalseOptimizedFalse) falseInfoWhenTrue.setReachMode(FlowInfo.UNREACHABLE); + + UnconditionalFlowInfo trueInfoWhenFalse = trueFlowInfo.initsWhenFalse().copy().unconditionalInits(); + if (isValueIfTrueOptimizedTrue) trueInfoWhenFalse.setReachMode(FlowInfo.UNREACHABLE); + + UnconditionalFlowInfo falseInfoWhenFalse = falseFlowInfo.initsWhenFalse().copy().unconditionalInits(); + if (isValueIfFalseOptimizedTrue) falseInfoWhenFalse.setReachMode(FlowInfo.UNREACHABLE); + + mergedInfo = + FlowInfo.conditional( + trueInfoWhenTrue.mergedWith(falseInfoWhenTrue), + trueInfoWhenFalse.mergedWith(falseInfoWhenFalse)); + } + mergedInitStateIndex = + currentScope.methodScope().recordInitializationStates(mergedInfo); + mergedInfo.setReachMode(mode); + return mergedInfo; + } + + /** + * Code generation for the conditional operator ?: + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ + public void generateCode( + BlockScope currentScope, + CodeStream codeStream, + boolean valueRequired) { + + int pc = codeStream.position; + Label endifLabel, falseLabel; + if (constant != NotAConstant) { + if (valueRequired) + codeStream.generateConstant(constant, implicitConversion); + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + Constant cst = condition.constant; + Constant condCst = condition.optimizedBooleanConstant(); + boolean needTruePart = + !(((cst != NotAConstant) && (cst.booleanValue() == false)) + || ((condCst != NotAConstant) && (condCst.booleanValue() == false))); + boolean needFalsePart = + !(((cst != NotAConstant) && (cst.booleanValue() == true)) + || ((condCst != NotAConstant) && (condCst.booleanValue() == true))); + endifLabel = new Label(codeStream); + + // Generate code for the condition + boolean needConditionValue = (cst == NotAConstant) && (condCst == NotAConstant); + condition.generateOptimizedBoolean( + currentScope, + codeStream, + null, + (falseLabel = new Label(codeStream)), + needConditionValue); + + if (trueInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + trueInitStateIndex); + codeStream.addDefinitelyAssignedVariables(currentScope, trueInitStateIndex); + } + // Then code generation + if (needTruePart) { + valueIfTrue.generateCode(currentScope, codeStream, valueRequired); + if (needFalsePart) { + // Jump over the else part + int position = codeStream.position; + codeStream.goto_(endifLabel); + codeStream.updateLastRecordedEndPC(position); + // Tune codestream stack size + if (valueRequired) { + codeStream.decrStackSize(this.resolvedType == LongBinding || this.resolvedType == DoubleBinding ? 2 : 1); + } + } + } + if (needFalsePart) { + falseLabel.place(); + if (falseInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + falseInitStateIndex); + codeStream.addDefinitelyAssignedVariables(currentScope, falseInitStateIndex); + } + valueIfFalse.generateCode(currentScope, codeStream, valueRequired); + // End of if statement + endifLabel.place(); + } + // May loose some local variable initializations : affecting the local variable attributes + if (mergedInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + mergedInitStateIndex); + } + // implicit conversion + if (valueRequired) + codeStream.generateImplicitConversion(implicitConversion); + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + /** + * Optimized boolean code generation for the conditional operator ?: + */ + public void generateOptimizedBoolean( + BlockScope currentScope, + CodeStream codeStream, + Label trueLabel, + Label falseLabel, + boolean valueRequired) { + + if ((constant != Constant.NotAConstant) && (constant.typeID() == T_boolean) // constant + || (valueIfTrue.implicitConversion >> 4) != T_boolean) { // non boolean values + super.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired); + return; + } + Constant cst = condition.constant; + Constant condCst = condition.optimizedBooleanConstant(); + boolean needTruePart = + !(((cst != NotAConstant) && (cst.booleanValue() == false)) + || ((condCst != NotAConstant) && (condCst.booleanValue() == false))); + boolean needFalsePart = + !(((cst != NotAConstant) && (cst.booleanValue() == true)) + || ((condCst != NotAConstant) && (condCst.booleanValue() == true))); + + Label internalFalseLabel, endifLabel = new Label(codeStream); + + // Generate code for the condition + boolean needConditionValue = (cst == NotAConstant) && (condCst == NotAConstant); + condition.generateOptimizedBoolean( + currentScope, + codeStream, + null, + internalFalseLabel = new Label(codeStream), + needConditionValue); + + if (trueInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + trueInitStateIndex); + codeStream.addDefinitelyAssignedVariables(currentScope, trueInitStateIndex); + } + // Then code generation + if (needTruePart) { + valueIfTrue.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired); + + if (needFalsePart) { + // Jump over the else part + int position = codeStream.position; + codeStream.goto_(endifLabel); + codeStream.updateLastRecordedEndPC(position); + // No need to decrement codestream stack size + // since valueIfTrue was already consumed by branch bytecode + } + } + if (needFalsePart) { + internalFalseLabel.place(); + if (falseInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + falseInitStateIndex); + codeStream.addDefinitelyAssignedVariables(currentScope, falseInitStateIndex); + } + valueIfFalse.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired); + + // End of if statement + endifLabel.place(); + } + // May loose some local variable initializations : affecting the local variable attributes + if (mergedInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + mergedInitStateIndex); + } + // no implicit conversion for boolean values + codeStream.updateLastRecordedEndPC(codeStream.position); + } + + public Constant optimizedBooleanConstant() { + + return this.optimizedBooleanConstant == null ? this.constant : this.optimizedBooleanConstant; + } + + public StringBuffer printExpressionNoParenthesis(int indent, StringBuffer output) { + + condition.printExpression(indent, output).append(" ? "); //$NON-NLS-1$ + valueIfTrue.printExpression(0, output).append(" : "); //$NON-NLS-1$ + return valueIfFalse.printExpression(0, output); + } + + public TypeBinding resolveType(BlockScope scope) { + // specs p.368 + constant = NotAConstant; + TypeBinding conditionType = condition.resolveTypeExpecting(scope, BooleanBinding); + + if (valueIfTrue instanceof CastExpression) valueIfTrue.bits |= IgnoreNeedForCastCheckMASK; // will check later on + TypeBinding valueIfTrueType = valueIfTrue.resolveType(scope); + + if (valueIfFalse instanceof CastExpression) valueIfFalse.bits |= IgnoreNeedForCastCheckMASK; // will check later on + TypeBinding valueIfFalseType = valueIfFalse.resolveType(scope); + + if (conditionType == null || valueIfTrueType == null || valueIfFalseType == null) + return null; + + // Propagate the constant value from the valueIfTrue and valueIFFalse expression if it is possible + Constant condConstant, trueConstant, falseConstant; + if ((condConstant = condition.constant) != NotAConstant + && (trueConstant = valueIfTrue.constant) != NotAConstant + && (falseConstant = valueIfFalse.constant) != NotAConstant) { + // all terms are constant expression so we can propagate the constant + // from valueIFTrue or valueIfFalse to teh receiver constant + constant = condConstant.booleanValue() ? trueConstant : falseConstant; + } + if (valueIfTrueType == valueIfFalseType) { // harmed the implicit conversion + valueIfTrue.implicitWidening(valueIfTrueType, valueIfTrueType); + valueIfFalse.implicitConversion = valueIfTrue.implicitConversion; + if (valueIfTrueType == BooleanBinding) { + this.optimizedIfTrueConstant = valueIfTrue.optimizedBooleanConstant(); + this.optimizedIfFalseConstant = valueIfFalse.optimizedBooleanConstant(); + if (this.optimizedIfTrueConstant != NotAConstant + && this.optimizedIfFalseConstant != NotAConstant + && this.optimizedIfTrueConstant.booleanValue() == this.optimizedIfFalseConstant.booleanValue()) { + // a ? true : true / a ? false : false + this.optimizedBooleanConstant = optimizedIfTrueConstant; + } else if ((condConstant = condition.optimizedBooleanConstant()) != NotAConstant) { // Propagate the optimized boolean constant if possible + this.optimizedBooleanConstant = condConstant.booleanValue() + ? this.optimizedIfTrueConstant + : this.optimizedIfFalseConstant; + } + } + return this.resolvedType = valueIfTrueType; + } + // Determine the return type depending on argument types + // Numeric types + if (valueIfTrueType.isNumericType() && valueIfFalseType.isNumericType()) { + // (Short x Byte) or (Byte x Short)" + if ((valueIfTrueType == ByteBinding && valueIfFalseType == ShortBinding) + || (valueIfTrueType == ShortBinding && valueIfFalseType == ByteBinding)) { + valueIfTrue.implicitWidening(ShortBinding, valueIfTrueType); + valueIfFalse.implicitWidening(ShortBinding, valueIfFalseType); + return this.resolvedType = ShortBinding; + } + // x constant(Int) ---> and reciprocally + if ((valueIfTrueType == ByteBinding || valueIfTrueType == ShortBinding || valueIfTrueType == CharBinding) + && (valueIfFalseType == IntBinding + && valueIfFalse.isConstantValueOfTypeAssignableToType(valueIfFalseType, valueIfTrueType))) { + valueIfTrue.implicitWidening(valueIfTrueType, valueIfTrueType); + valueIfFalse.implicitWidening(valueIfTrueType, valueIfFalseType); + return this.resolvedType = valueIfTrueType; + } + if ((valueIfFalseType == ByteBinding + || valueIfFalseType == ShortBinding + || valueIfFalseType == CharBinding) + && (valueIfTrueType == IntBinding + && valueIfTrue.isConstantValueOfTypeAssignableToType(valueIfTrueType, valueIfFalseType))) { + valueIfTrue.implicitWidening(valueIfFalseType, valueIfTrueType); + valueIfFalse.implicitWidening(valueIfFalseType, valueIfFalseType); + return this.resolvedType = valueIfFalseType; + } + // Manual binary numeric promotion + // int + if (BaseTypeBinding.isNarrowing(valueIfTrueType.id, T_int) + && BaseTypeBinding.isNarrowing(valueIfFalseType.id, T_int)) { + valueIfTrue.implicitWidening(IntBinding, valueIfTrueType); + valueIfFalse.implicitWidening(IntBinding, valueIfFalseType); + return this.resolvedType = IntBinding; + } + // long + if (BaseTypeBinding.isNarrowing(valueIfTrueType.id, T_long) + && BaseTypeBinding.isNarrowing(valueIfFalseType.id, T_long)) { + valueIfTrue.implicitWidening(LongBinding, valueIfTrueType); + valueIfFalse.implicitWidening(LongBinding, valueIfFalseType); + return this.resolvedType = LongBinding; + } + // float + if (BaseTypeBinding.isNarrowing(valueIfTrueType.id, T_float) + && BaseTypeBinding.isNarrowing(valueIfFalseType.id, T_float)) { + valueIfTrue.implicitWidening(FloatBinding, valueIfTrueType); + valueIfFalse.implicitWidening(FloatBinding, valueIfFalseType); + return this.resolvedType = FloatBinding; + } + // double + valueIfTrue.implicitWidening(DoubleBinding, valueIfTrueType); + valueIfFalse.implicitWidening(DoubleBinding, valueIfFalseType); + return this.resolvedType = DoubleBinding; + } + // Type references (null null is already tested) + if ((valueIfTrueType.isBaseType() && valueIfTrueType != NullBinding) + || (valueIfFalseType.isBaseType() && valueIfFalseType != NullBinding)) { + scope.problemReporter().conditionalArgumentsIncompatibleTypes( + this, + valueIfTrueType, + valueIfFalseType); + return null; + } + if (valueIfFalseType.isCompatibleWith(valueIfTrueType)) { + valueIfTrue.implicitWidening(valueIfTrueType, valueIfTrueType); + valueIfFalse.implicitWidening(valueIfTrueType, valueIfFalseType); + return this.resolvedType = valueIfTrueType; + } + if (valueIfTrueType.isCompatibleWith(valueIfFalseType)) { + valueIfTrue.implicitWidening(valueIfFalseType, valueIfTrueType); + valueIfFalse.implicitWidening(valueIfFalseType, valueIfFalseType); + return this.resolvedType = valueIfFalseType; + } + scope.problemReporter().conditionalArgumentsIncompatibleTypes( + this, + valueIfTrueType, + valueIfFalseType); + return null; + } + + public void traverse(ASTVisitor visitor, BlockScope scope) { + if (visitor.visit(this, scope)) { + condition.traverse(visitor, scope); + valueIfTrue.traverse(visitor, scope); + valueIfFalse.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java b/src/java/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java new file mode 100644 index 0000000..7170bbf --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java @@ -0,0 +1,454 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import java.util.ArrayList; + +import org.eclipse.jdt.core.compiler.*; +import org.eclipse.jdt.internal.compiler.*; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; +import org.eclipse.jdt.internal.compiler.parser.*; +import org.eclipse.jdt.internal.compiler.problem.*; + +public class ConstructorDeclaration extends AbstractMethodDeclaration { + + public ExplicitConstructorCall constructorCall; + public final static char[] ConstantPoolName = "".toCharArray(); //$NON-NLS-1$ + public boolean isDefaultConstructor = false; + + public ConstructorDeclaration(CompilationResult compilationResult){ + super(compilationResult); + } + + public void analyseCode( + ClassScope classScope, + InitializationFlowContext initializerFlowContext, + FlowInfo flowInfo) { + + if (ignoreFurtherInvestigation) + return; + + if (this.binding != null && this.binding.isPrivate() && !this.binding.isPrivateUsed()) { + if (!classScope.referenceCompilationUnit().compilationResult.hasSyntaxError()) { + scope.problemReporter().unusedPrivateConstructor(this); + } + } + + // check constructor recursion, once all constructor got resolved + if (isRecursive(null /*lazy initialized visited list*/)) { + this.scope.problemReporter().recursiveConstructorInvocation(this.constructorCall); + } + + try { + ExceptionHandlingFlowContext constructorContext = + new ExceptionHandlingFlowContext( + initializerFlowContext.parent, + this, + binding.thrownExceptions, + scope, + FlowInfo.DEAD_END); + initializerFlowContext.checkInitializerExceptions( + scope, + constructorContext, + flowInfo); + + // anonymous constructor can gain extra thrown exceptions from unhandled ones + if (binding.declaringClass.isAnonymousType()) { + ArrayList computedExceptions = constructorContext.extendedExceptions; + if (computedExceptions != null){ + int size; + if ((size = computedExceptions.size()) > 0){ + ReferenceBinding[] actuallyThrownExceptions; + computedExceptions.toArray(actuallyThrownExceptions = new ReferenceBinding[size]); + binding.thrownExceptions = actuallyThrownExceptions; + } + } + } + + // propagate to constructor call + if (constructorCall != null) { + // if calling 'this(...)', then flag all non-static fields as definitely + // set since they are supposed to be set inside other local constructor + if (constructorCall.accessMode == ExplicitConstructorCall.This) { + FieldBinding[] fields = binding.declaringClass.fields(); + for (int i = 0, count = fields.length; i < count; i++) { + FieldBinding field; + if (!(field = fields[i]).isStatic()) { + flowInfo.markAsDefinitelyAssigned(field); + } + } + } + flowInfo = constructorCall.analyseCode(scope, constructorContext, flowInfo); + } + // propagate to statements + if (statements != null) { + boolean didAlreadyComplain = false; + for (int i = 0, count = statements.length; i < count; i++) { + Statement stat = statements[i]; + if (!stat.complainIfUnreachable(flowInfo, scope, didAlreadyComplain)) { + flowInfo = stat.analyseCode(scope, constructorContext, flowInfo); + } else { + didAlreadyComplain = true; + } + } + } + // check for missing returning path + this.needFreeReturn = flowInfo.isReachable(); + + // check missing blank final field initializations + if ((constructorCall != null) + && (constructorCall.accessMode != ExplicitConstructorCall.This)) { + flowInfo = flowInfo.mergedWith(constructorContext.initsOnReturn); + FieldBinding[] fields = binding.declaringClass.fields(); + for (int i = 0, count = fields.length; i < count; i++) { + FieldBinding field; + if ((!(field = fields[i]).isStatic()) + && field.isFinal() + && (!flowInfo.isDefinitelyAssigned(fields[i]))) { + scope.problemReporter().uninitializedBlankFinalField( + field, + isDefaultConstructor ? (ASTNode) scope.referenceType() : this); + } + } + } + // check unreachable catch blocks + constructorContext.complainIfUnusedExceptionHandlers(this); + } catch (AbortMethod e) { + this.ignoreFurtherInvestigation = true; + } + } + + /** + * Bytecode generation for a constructor + * + * @param classScope org.eclipse.jdt.internal.compiler.lookup.ClassScope + * @param classFile org.eclipse.jdt.internal.compiler.codegen.ClassFile + */ + public void generateCode(ClassScope classScope, ClassFile classFile) { + + int problemResetPC = 0; + if (ignoreFurtherInvestigation) { + if (this.binding == null) + return; // Handle methods with invalid signature or duplicates + int problemsLength; + IProblem[] problems = + scope.referenceCompilationUnit().compilationResult.getProblems(); + IProblem[] problemsCopy = new IProblem[problemsLength = problems.length]; + System.arraycopy(problems, 0, problemsCopy, 0, problemsLength); + classFile.addProblemConstructor(this, binding, problemsCopy); + return; + } + try { + problemResetPC = classFile.contentsOffset; + this.internalGenerateCode(classScope, classFile); + } catch (AbortMethod e) { + if (e.compilationResult == CodeStream.RESTART_IN_WIDE_MODE) { + // a branch target required a goto_w, restart code gen in wide mode. + try { + classFile.contentsOffset = problemResetPC; + classFile.methodCount--; + classFile.codeStream.wideMode = true; // request wide mode + this.internalGenerateCode(classScope, classFile); // restart method generation + } catch (AbortMethod e2) { + int problemsLength; + IProblem[] problems = + scope.referenceCompilationUnit().compilationResult.getAllProblems(); + IProblem[] problemsCopy = new IProblem[problemsLength = problems.length]; + System.arraycopy(problems, 0, problemsCopy, 0, problemsLength); + classFile.addProblemConstructor(this, binding, problemsCopy, problemResetPC); + } + } else { + int problemsLength; + IProblem[] problems = + scope.referenceCompilationUnit().compilationResult.getAllProblems(); + IProblem[] problemsCopy = new IProblem[problemsLength = problems.length]; + System.arraycopy(problems, 0, problemsCopy, 0, problemsLength); + classFile.addProblemConstructor(this, binding, problemsCopy, problemResetPC); + } + } + } + + public void generateSyntheticFieldInitializationsIfNecessary( + MethodScope methodScope, + CodeStream codeStream, + ReferenceBinding declaringClass) { + + if (!declaringClass.isNestedType()) return; + + NestedTypeBinding nestedType = (NestedTypeBinding) declaringClass; + + SyntheticArgumentBinding[] syntheticArgs = nestedType.syntheticEnclosingInstances(); + for (int i = 0, max = syntheticArgs == null ? 0 : syntheticArgs.length; i < max; i++) { + SyntheticArgumentBinding syntheticArg; + if ((syntheticArg = syntheticArgs[i]).matchingField != null) { + codeStream.aload_0(); + codeStream.load(syntheticArg); + codeStream.putfield(syntheticArg.matchingField); + } + } + syntheticArgs = nestedType.syntheticOuterLocalVariables(); + for (int i = 0, max = syntheticArgs == null ? 0 : syntheticArgs.length; i < max; i++) { + SyntheticArgumentBinding syntheticArg; + if ((syntheticArg = syntheticArgs[i]).matchingField != null) { + codeStream.aload_0(); + codeStream.load(syntheticArg); + codeStream.putfield(syntheticArg.matchingField); + } + } + } + + private void internalGenerateCode(ClassScope classScope, ClassFile classFile) { + + classFile.generateMethodInfoHeader(binding); + int methodAttributeOffset = classFile.contentsOffset; + int attributeNumber = classFile.generateMethodInfoAttribute(binding); + if ((!binding.isNative()) && (!binding.isAbstract())) { + + TypeDeclaration declaringType = classScope.referenceContext; + int codeAttributeOffset = classFile.contentsOffset; + classFile.generateCodeAttributeHeader(); + CodeStream codeStream = classFile.codeStream; + codeStream.reset(this, classFile); + + // initialize local positions - including initializer scope. + ReferenceBinding declaringClass = binding.declaringClass; + + int argSlotSize = 1; // this==aload0 + + if (declaringClass.isNestedType()){ + NestedTypeBinding nestedType = (NestedTypeBinding) declaringClass; + this.scope.extraSyntheticArguments = nestedType.syntheticOuterLocalVariables(); + scope.computeLocalVariablePositions(// consider synthetic arguments if any + nestedType.enclosingInstancesSlotSize + 1, + codeStream); + argSlotSize += nestedType.enclosingInstancesSlotSize; + argSlotSize += nestedType.outerLocalVariablesSlotSize; + } else { + scope.computeLocalVariablePositions(1, codeStream); + } + + if (arguments != null) { + for (int i = 0, max = arguments.length; i < max; i++) { + // arguments initialization for local variable debug attributes + LocalVariableBinding argBinding; + codeStream.addVisibleLocalVariable(argBinding = arguments[i].binding); + argBinding.recordInitializationStartPC(0); + TypeBinding argType; + if ((argType = argBinding.type) == LongBinding || (argType == DoubleBinding)) { + argSlotSize += 2; + } else { + argSlotSize++; + } + } + } + + MethodScope initializerScope = declaringType.initializerScope; + initializerScope.computeLocalVariablePositions(argSlotSize, codeStream); // offset by the argument size (since not linked to method scope) + + boolean needFieldInitializations = constructorCall == null || constructorCall.accessMode != ExplicitConstructorCall.This; + + // post 1.4 source level, synthetic initializations occur prior to explicit constructor call + boolean preInitSyntheticFields = scope.environment().options.targetJDK >= ClassFileConstants.JDK1_4; + + if (needFieldInitializations && preInitSyntheticFields){ + generateSyntheticFieldInitializationsIfNecessary(scope, codeStream, declaringClass); + } + // generate constructor call + if (constructorCall != null) { + constructorCall.generateCode(scope, codeStream); + } + // generate field initialization - only if not invoking another constructor call of the same class + if (needFieldInitializations) { + if (!preInitSyntheticFields){ + generateSyntheticFieldInitializationsIfNecessary(scope, codeStream, declaringClass); + } + // generate user field initialization + if (declaringType.fields != null) { + for (int i = 0, max = declaringType.fields.length; i < max; i++) { + FieldDeclaration fieldDecl; + if (!(fieldDecl = declaringType.fields[i]).isStatic()) { + fieldDecl.generateCode(initializerScope, codeStream); + } + } + } + } + // generate statements + if (statements != null) { + for (int i = 0, max = statements.length; i < max; i++) { + statements[i].generateCode(scope, codeStream); + } + } + if (this.needFreeReturn) { + codeStream.return_(); + } + // local variable attributes + codeStream.exitUserScope(scope); + codeStream.recordPositionsFrom(0, this.bodyEnd); + classFile.completeCodeAttribute(codeAttributeOffset); + attributeNumber++; + } + classFile.completeMethodInfo(methodAttributeOffset, attributeNumber); + + // if a problem got reported during code gen, then trigger problem method creation + if (ignoreFurtherInvestigation) { + throw new AbortMethod(scope.referenceCompilationUnit().compilationResult, null); + } + } + + public boolean isConstructor() { + + return true; + } + + public boolean isDefaultConstructor() { + + return this.isDefaultConstructor; + } + + public boolean isInitializationMethod() { + + return true; + } + + /** + * Returns true if the constructor is directly involved in a cycle. + * Given most constructors aren't, we only allocate the visited list + * lazily. + * + * @param visited + * @return + */ + public boolean isRecursive(ArrayList visited) { + + if (this.binding == null + || this.constructorCall == null + || this.constructorCall.binding == null + || this.constructorCall.isSuperAccess() + || !this.constructorCall.binding.isValidBinding()) { + return false; + } + + ConstructorDeclaration targetConstructor = + ((ConstructorDeclaration)this.scope.referenceType().declarationOf(constructorCall.binding)); + if (this == targetConstructor) return true; // direct case + + if (visited == null) { // lazy allocation + visited = new ArrayList(1); + } else { + int index = visited.indexOf(this); + if (index >= 0) return index == 0; // only blame if directly part of the cycle + } + visited.add(this); + + return targetConstructor.isRecursive(visited); + } + + public void parseStatements(Parser parser, CompilationUnitDeclaration unit) { + + //fill up the constructor body with its statements + if (ignoreFurtherInvestigation) + return; + if (isDefaultConstructor){ + constructorCall = SuperReference.implicitSuperConstructorCall(); + constructorCall.sourceStart = sourceStart; + constructorCall.sourceEnd = sourceEnd; + return; + } + parser.parse(this, unit); + + } + + public StringBuffer printBody(int indent, StringBuffer output) { + + output.append(" {"); //$NON-NLS-1$ + if (constructorCall != null) { + output.append('\n'); + constructorCall.printStatement(indent, output); //$NON-NLS-1$ //$NON-NLS-2$ + } + if (statements != null) { + for (int i = 0; i < statements.length; i++) { + output.append('\n'); + statements[i].printStatement(indent, output); //$NON-NLS-1$ + } + } + output.append('\n'); + printIndent(indent == 0 ? 0 : indent - 1, output).append('}'); + return output; + } + + public void resolveJavadoc() { + + if (this.binding == null || this.javadoc != null) { + super.resolveJavadoc(); + } else if (!isDefaultConstructor) { + this.scope.problemReporter().javadocMissing(this.sourceStart, this.sourceEnd, this.binding.modifiers); + } + } + + /* + * Type checking for constructor, just another method, except for special check + * for recursive constructor invocations. + */ + public void resolveStatements() { + + if (!CharOperation.equals(scope.enclosingSourceType().sourceName, selector)){ + scope.problemReporter().missingReturnType(this); + } + + // if null ==> an error has occurs at parsing time .... + if (this.constructorCall != null) { + // e.g. using super() in java.lang.Object + if (this.binding != null + && this.binding.declaringClass.id == T_Object + && this.constructorCall.accessMode != ExplicitConstructorCall.This) { + if (this.constructorCall.accessMode == ExplicitConstructorCall.Super) { + scope.problemReporter().cannotUseSuperInJavaLangObject(this.constructorCall); + } + this.constructorCall = null; + } else { + this.constructorCall.resolve(this.scope); + } + } + if ((modifiers & AccSemicolonBody) != 0) { + scope.problemReporter().methodNeedBody(this); + } + super.resolveStatements(); + } + + public void traverse( + ASTVisitor visitor, + ClassScope classScope) { + + if (visitor.visit(this, classScope)) { + if (arguments != null) { + int argumentLength = arguments.length; + for (int i = 0; i < argumentLength; i++) + arguments[i].traverse(visitor, scope); + } + if (thrownExceptions != null) { + int thrownExceptionsLength = thrownExceptions.length; + for (int i = 0; i < thrownExceptionsLength; i++) + thrownExceptions[i].traverse(visitor, scope); + } + if (constructorCall != null) + constructorCall.traverse(visitor, scope); + if (statements != null) { + int statementsLength = statements.length; + for (int i = 0; i < statementsLength; i++) + statements[i].traverse(visitor, scope); + } + } + visitor.endVisit(this, classScope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/ContinueStatement.java b/src/java/org/eclipse/jdt/internal/compiler/ast/ContinueStatement.java new file mode 100644 index 0000000..83831b3 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/ContinueStatement.java @@ -0,0 +1,100 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class ContinueStatement extends BranchStatement { + + public ContinueStatement(char[] l, int s, int e) { + + super(l, s, e); + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + // here requires to generate a sequence of finally blocks invocations depending corresponding + // to each of the traversed try statements, so that execution will terminate properly. + + // lookup the label, this should answer the returnContext + FlowContext targetContext = (label == null) + ? flowContext.getTargetContextForDefaultContinue() + : flowContext.getTargetContextForContinueLabel(label); + + if (targetContext == null) { + if (label == null) { + currentScope.problemReporter().invalidContinue(this); + } else { + currentScope.problemReporter().undefinedLabel(this); + } + return flowInfo; // pretend it did not continue since no actual target + } + + if (targetContext == FlowContext.NotContinuableContext) { + currentScope.problemReporter().invalidContinue(this); + return flowInfo; // pretend it did not continue since no actual target + } + targetLabel = targetContext.continueLabel(); + FlowContext traversedContext = flowContext; + int subIndex = 0, maxSub = 5; + subroutines = new SubRoutineStatement[maxSub]; + + do { + SubRoutineStatement sub; + if ((sub = traversedContext.subRoutine()) != null) { + if (subIndex == maxSub) { + System.arraycopy(subroutines, 0, (subroutines = new SubRoutineStatement[maxSub*=2]), 0, subIndex); // grow + } + subroutines[subIndex++] = sub; + if (sub.isSubRoutineEscaping()) { + break; + } + } + traversedContext.recordReturnFrom(flowInfo.unconditionalInits()); + + ASTNode node; + if ((node = traversedContext.associatedNode) instanceof TryStatement) { + TryStatement tryStatement = (TryStatement) node; + flowInfo.addInitializationsFrom(tryStatement.subRoutineInits); // collect inits + } else if (traversedContext == targetContext) { + // only record continue info once accumulated through subroutines, and only against target context + targetContext.recordContinueFrom(flowInfo); + break; + } + } while ((traversedContext = traversedContext.parent) != null); + + // resize subroutines + if (subIndex != maxSub) { + System.arraycopy(subroutines, 0, (subroutines = new SubRoutineStatement[subIndex]), 0, subIndex); + } + return FlowInfo.DEAD_END; + } + + public StringBuffer printStatement(int tab, StringBuffer output) { + + printIndent(tab, output).append("continue "); //$NON-NLS-1$ + if (label != null) output.append(label); + return output.append(';'); + } + + public void traverse( + ASTVisitor visitor, + BlockScope blockScope) { + + visitor.visit(this, blockScope); + visitor.endVisit(this, blockScope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/DoStatement.java b/src/java/org/eclipse/jdt/internal/compiler/ast/DoStatement.java new file mode 100644 index 0000000..0dc995d --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/DoStatement.java @@ -0,0 +1,173 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class DoStatement extends Statement { + + public Expression condition; + public Statement action; + + private Label breakLabel, continueLabel; + + // for local variables table attributes + int mergedInitStateIndex = -1; + + public DoStatement(Expression condition, Statement action, int s, int e) { + + this.sourceStart = s; + this.sourceEnd = e; + this.condition = condition; + this.action = action; + // remember useful empty statement + if (action instanceof EmptyStatement) action.bits |= IsUsefulEmptyStatementMASK; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + breakLabel = new Label(); + continueLabel = new Label(); + LoopingFlowContext loopingContext = + new LoopingFlowContext( + flowContext, + this, + breakLabel, + continueLabel, + currentScope); + + Constant cst = condition.constant; + boolean isConditionTrue = cst != NotAConstant && cst.booleanValue() == true; + cst = condition.optimizedBooleanConstant(); + boolean isConditionOptimizedTrue = cst != NotAConstant && cst.booleanValue() == true; + boolean isConditionOptimizedFalse = cst != NotAConstant && cst.booleanValue() == false; + + int previousMode = flowInfo.reachMode(); + + if ((action != null) && !action.isEmptyBlock()) { + flowInfo = action.analyseCode(currentScope, loopingContext, flowInfo); + + // code generation can be optimized when no need to continue in the loop + if (!flowInfo.isReachable() && !loopingContext.initsOnContinue.isReachable()) { + continueLabel = null; + } + } + /* Reset reach mode, to address following scenario. + * final blank; + * do { if (true) break; else blank = 0; } while(false); + * blank = 1; // may be initialized already + */ + flowInfo.setReachMode(previousMode); + + flowInfo = + condition.analyseCode( + currentScope, + loopingContext, + (action == null + ? flowInfo + : (flowInfo.mergedWith(loopingContext.initsOnContinue)))); + if (!isConditionOptimizedFalse && continueLabel != null) { + loopingContext.complainOnFinalAssignmentsInLoop(currentScope, flowInfo); + } + + // end of loop + FlowInfo mergedInfo = FlowInfo.mergedOptimizedBranches( + loopingContext.initsOnBreak, + isConditionOptimizedTrue, + flowInfo.initsWhenFalse(), + false, // never consider opt false case for DO loop, since break can always occur (47776) + !isConditionTrue /*do{}while(true); unreachable(); */); + mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo); + return mergedInfo; + } + + /** + * Do statement code generation + * + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + + if ((bits & IsReachableMASK) == 0) { + return; + } + int pc = codeStream.position; + + // labels management + Label actionLabel = new Label(codeStream); + actionLabel.place(); + breakLabel.initialize(codeStream); + if (continueLabel != null) { + continueLabel.initialize(codeStream); + } + + // generate action + if (action != null) { + action.generateCode(currentScope, codeStream); + } + // generate condition + if (continueLabel != null) { + continueLabel.place(); + condition.generateOptimizedBoolean( + currentScope, + codeStream, + actionLabel, + null, + true); + } + breakLabel.place(); + + // May loose some local variable initializations : affecting the local variable attributes + if (mergedInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables(currentScope, mergedInitStateIndex); + codeStream.addDefinitelyAssignedVariables(currentScope, mergedInitStateIndex); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + + } + + public StringBuffer printStatement(int indent, StringBuffer output) { + + printIndent(indent, output).append("do"); //$NON-NLS-1$ + if (action == null) + output.append(" ;\n"); //$NON-NLS-1$ + else { + output.append('\n'); + action.printStatement(indent + 1, output).append('\n'); + } + output.append("while ("); //$NON-NLS-1$ + return condition.printExpression(0, output).append(");"); //$NON-NLS-1$ + } + public void resolve(BlockScope scope) { + + TypeBinding type = condition.resolveTypeExpecting(scope, BooleanBinding); + condition.implicitWidening(type, type); + if (action != null) + action.resolve(scope); + } + + public void traverse(ASTVisitor visitor, BlockScope scope) { + + if (visitor.visit(this, scope)) { + if (action != null) { + action.traverse(visitor, scope); + } + condition.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/DoubleLiteral.java b/src/java/org/eclipse/jdt/internal/compiler/ast/DoubleLiteral.java new file mode 100644 index 0000000..139c813 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/DoubleLiteral.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class DoubleLiteral extends NumberLiteral { + double value; +public DoubleLiteral(char[] token, int s, int e) { + super(token, s,e); +} +public void computeConstant() { + + //the source is correctly formated so the exception should never occurs + + Double computedValue; + try { computedValue = Double.valueOf(String.valueOf(source));} + catch(NumberFormatException e){return ;} //how can it happen ???? + + if (computedValue.doubleValue() > Double.MAX_VALUE) return ; //may be Infinity + if (computedValue.doubleValue() < Double.MIN_VALUE) + { //only a true 0 can be made of zeros + //2.00000000000000000e-324 is illegal .... + label : + for (int i=0;i> 4) == T_double) + codeStream.generateInlinedValue(value); + else + codeStream.generateConstant(constant, implicitConversion); + codeStream.recordPositionsFrom(pc, this.sourceStart); +} +public TypeBinding literalType(BlockScope scope) { + return DoubleBinding; +} +public void traverse(ASTVisitor visitor, BlockScope blockScope) { + visitor.visit(this, blockScope); + visitor.endVisit(this, blockScope); +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/EmptyStatement.java b/src/java/org/eclipse/jdt/internal/compiler/ast/EmptyStatement.java new file mode 100644 index 0000000..bd570e6 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/EmptyStatement.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.lookup.BlockScope; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.codegen.CodeStream; +import org.eclipse.jdt.internal.compiler.flow.FlowContext; +import org.eclipse.jdt.internal.compiler.flow.FlowInfo; +import org.eclipse.jdt.internal.compiler.ASTVisitor; + +public class EmptyStatement extends Statement { + + public EmptyStatement(int startPosition, int endPosition) { + this.sourceStart = startPosition; + this.sourceEnd = endPosition; + } + + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + return flowInfo; + } + + // Report an error if necessary + public boolean complainIfUnreachable(FlowInfo flowInfo, BlockScope scope, boolean didAlreadyComplain) { + + // before 1.4, empty statements are tolerated anywhere + if (scope.environment().options.complianceLevel < ClassFileConstants.JDK1_4) { + return false; + } + return super.complainIfUnreachable(flowInfo, scope, didAlreadyComplain); + } + + public void generateCode(BlockScope currentScope, CodeStream codeStream){ + // no bytecode, no need to check for reachability or recording source positions + } + + public StringBuffer printStatement(int tab, StringBuffer output) { + return printIndent(tab, output).append(';'); + } + + public void resolve(BlockScope scope) { + if ((bits & IsUsefulEmptyStatementMASK) == 0) { + scope.problemReporter().superfluousSemicolon(this.sourceStart, this.sourceEnd); + } else { + scope.problemReporter().emptyControlFlowStatement(this.sourceStart, this.sourceEnd); + } + } + + public void traverse(ASTVisitor visitor, BlockScope scope) { + visitor.visit(this, scope); + visitor.endVisit(this, scope); + } + + +} + diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java b/src/java/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java new file mode 100644 index 0000000..0caeb81 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java @@ -0,0 +1,578 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class EqualExpression extends BinaryExpression { + +public EqualExpression(Expression left, Expression right,int operator) { + super(left,right,operator); +} +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + if (((bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) { + if ((left.constant != NotAConstant) && (left.constant.typeID() == T_boolean)) { + if (left.constant.booleanValue()) { // true == anything + // this is equivalent to the right argument inits + return right.analyseCode(currentScope, flowContext, flowInfo); + } else { // false == anything + // this is equivalent to the right argument inits negated + return right.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition(); + } + } + if ((right.constant != NotAConstant) && (right.constant.typeID() == T_boolean)) { + if (right.constant.booleanValue()) { // anything == true + // this is equivalent to the right argument inits + return left.analyseCode(currentScope, flowContext, flowInfo); + } else { // anything == false + // this is equivalent to the right argument inits negated + return left.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition(); + } + } + return right.analyseCode( + currentScope, flowContext, + left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits()).unconditionalInits(); + } else { //NOT_EQUAL : + if ((left.constant != NotAConstant) && (left.constant.typeID() == T_boolean)) { + if (!left.constant.booleanValue()) { // false != anything + // this is equivalent to the right argument inits + return right.analyseCode(currentScope, flowContext, flowInfo); + } else { // true != anything + // this is equivalent to the right argument inits negated + return right.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition(); + } + } + if ((right.constant != NotAConstant) && (right.constant.typeID() == T_boolean)) { + if (!right.constant.booleanValue()) { // anything != false + // this is equivalent to the right argument inits + return left.analyseCode(currentScope, flowContext, flowInfo); + } else { // anything != true + // this is equivalent to the right argument inits negated + return left.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition(); + } + } + return right.analyseCode( + currentScope, flowContext, + left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits()).asNegatedCondition().unconditionalInits(); + } +} +public final boolean areTypesCastCompatible(BlockScope scope, TypeBinding castType, TypeBinding expressionType) { + //see specifications 5.5 + //A more complete version of this method is provided on + //CastExpression (it deals with constant and need runtime checkcast) + + if (castType == expressionType) return true; + + //========ARRAY=============== + if (expressionType.isArrayType()) { + if (castType.isArrayType()) { //------- (castTb.isArray) expressionTb.isArray ----------- + TypeBinding expressionEltType = ((ArrayBinding) expressionType).elementsType(scope); + if (expressionEltType.isBaseType()) + // <---stop the recursion------- + return ((ArrayBinding) castType).elementsType(scope) == expressionEltType; + //recursivly on the elts... + return areTypesCastCompatible(scope, ((ArrayBinding) castType).elementsType(scope), expressionEltType); + } + if (castType.isBaseType()) { + return false; + } + if (castType.isClass()) { //------(castTb.isClass) expressionTb.isArray --------------- + if (castType.id == T_Object) + return true; + return false; + } + if (castType.isInterface()) { //------- (castTb.isInterface) expressionTb.isArray ----------- + if (castType.id == T_JavaLangCloneable || castType.id == T_JavaIoSerializable) { + return true; + } + return false; + } + + return false; + } + + //------------(castType) null-------------- + if (expressionType == NullBinding) { + return !castType.isBaseType(); + } + + //========BASETYPE============== + if (expressionType.isBaseType()) { + return false; + } + + + //========REFERENCE TYPE=================== + + if (expressionType.isClass()) { + if (castType.isArrayType()) { // ---- (castTb.isArray) expressionTb.isClass ------- + if (expressionType.id == T_Object) + return true; + } + if (castType.isBaseType()) { + return false; + } + if (castType.isClass()) { // ----- (castTb.isClass) expressionTb.isClass ------ + if (expressionType.isCompatibleWith(castType)) + return true; + else { + if (castType.isCompatibleWith(expressionType)) { + return true; + } + return false; + } + } + if (castType.isInterface()) { // ----- (castTb.isInterface) expressionTb.isClass ------- + if (expressionType.isCompatibleWith(castType)) + return true; + if (!((ReferenceBinding) expressionType).isFinal()) { + return true; + } + //no subclass for expressionTb, thus compile-time check is valid + } + + return false; + } + if (expressionType.isInterface()) { + if (castType.isArrayType()) { // ----- (castTb.isArray) expressionTb.isInterface ------ + if (expressionType.id == T_JavaLangCloneable || expressionType.id == T_JavaIoSerializable) + //potential runtime error + { + return true; + } + return false; + } + if (castType.isBaseType()) { + return false; + } + if (castType.isClass()) { // ----- (castTb.isClass) expressionTb.isInterface -------- + if (castType.id == T_Object) + return true; + if (((ReferenceBinding) castType).isFinal()) { //no subclass for castTb, thus compile-time check is valid + if (castType.isCompatibleWith(expressionType)) { + return true; + } + return false; + } + return true; + } + if (castType.isInterface()) { // ----- (castTb.isInterface) expressionTb.isInterface ------- + if (expressionType.isCompatibleWith(castType)) + return true; + if (!castType.isCompatibleWith(expressionType)) { + MethodBinding[] castTbMethods = ((ReferenceBinding) castType).methods(); + int castTbMethodsLength = castTbMethods.length; + MethodBinding[] expressionTbMethods = ((ReferenceBinding) expressionType).methods(); + int expressionTbMethodsLength = expressionTbMethods.length; + for (int i = 0; i < castTbMethodsLength; i++) { + for (int j = 0; j < expressionTbMethodsLength; j++) { + if (CharOperation.equals(castTbMethods[i].selector, expressionTbMethods[j].selector)) { + if (castTbMethods[i].returnType != expressionTbMethods[j].returnType) { + if (castTbMethods[i].areParametersEqual(expressionTbMethods[j])) { + return false; + } + } + } + } + } + } + return true; + } + return false; + } + return false; +} +public final void computeConstant(TypeBinding leftType, TypeBinding rightType) { + if ((this.left.constant != NotAConstant) && (this.right.constant != NotAConstant)) { + this.constant = + Constant.computeConstantOperationEQUAL_EQUAL( + left.constant, + leftType.id, + EQUAL_EQUAL, + right.constant, + rightType.id); + if (((this.bits & OperatorMASK) >> OperatorSHIFT) == NOT_EQUAL) + constant = Constant.fromValue(!constant.booleanValue()); + } else { + this.constant = NotAConstant; + // no optimization for null == null + } +} +/** + * Normal == or != code generation. + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ +public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { + + if (constant != NotAConstant) { + int pc = codeStream.position; + if (valueRequired) + codeStream.generateConstant(constant, implicitConversion); + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + Label falseLabel; + bits |= OnlyValueRequiredMASK; + generateOptimizedBoolean( + currentScope, + codeStream, + null, + falseLabel = new Label(codeStream), + valueRequired); + if (falseLabel.hasForwardReferences()) { + if (valueRequired){ + // comparison is TRUE + codeStream.iconst_1(); + if ((bits & ValueForReturnMASK) != 0){ + codeStream.ireturn(); + // comparison is FALSE + falseLabel.place(); + codeStream.iconst_0(); + } else { + Label endLabel = new Label(codeStream); + codeStream.goto_(endLabel); + codeStream.decrStackSize(1); + // comparison is FALSE + falseLabel.place(); + codeStream.iconst_0(); + endLabel.place(); + } + } else { + falseLabel.place(); + } + } +} +/** + * Boolean operator code generation + * Optimized operations are: == and != + */ +public void generateOptimizedBoolean(BlockScope currentScope, CodeStream codeStream, Label trueLabel, Label falseLabel, boolean valueRequired) { + + if (constant != Constant.NotAConstant) { + super.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired); + return; + } + if (((bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) { + if ((left.implicitConversion & 0xF) /*compile-time*/ == T_boolean) { + generateOptimizedBooleanEqual(currentScope, codeStream, trueLabel, falseLabel, valueRequired); + } else { + generateOptimizedNonBooleanEqual(currentScope, codeStream, trueLabel, falseLabel, valueRequired); + } + } else { + if ((left.implicitConversion & 0xF) /*compile-time*/ == T_boolean) { + generateOptimizedBooleanEqual(currentScope, codeStream, falseLabel, trueLabel, valueRequired); + } else { + generateOptimizedNonBooleanEqual(currentScope, codeStream, falseLabel, trueLabel, valueRequired); + } + } +} +/** + * Boolean generation for == with boolean operands + * + * Note this code does not optimize conditional constants !!!! + */ +public void generateOptimizedBooleanEqual(BlockScope currentScope, CodeStream codeStream, Label trueLabel, Label falseLabel, boolean valueRequired) { + + // optimized cases: true == x, false == x + if (left.constant != NotAConstant) { + boolean inline = left.constant.booleanValue(); + right.generateOptimizedBoolean(currentScope, codeStream, (inline ? trueLabel : falseLabel), (inline ? falseLabel : trueLabel), valueRequired); + return; + } // optimized cases: x == true, x == false + if (right.constant != NotAConstant) { + boolean inline = right.constant.booleanValue(); + left.generateOptimizedBoolean(currentScope, codeStream, (inline ? trueLabel : falseLabel), (inline ? falseLabel : trueLabel), valueRequired); + return; + } + // default case + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicit falling through the FALSE case + codeStream.if_icmpeq(trueLabel); + } + } else { + // implicit falling through the TRUE case + if (trueLabel == null) { + codeStream.if_icmpne(falseLabel); + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + // reposition the endPC + codeStream.updateLastRecordedEndPC(codeStream.position); +} +/** + * Boolean generation for == with non-boolean operands + * + */ +public void generateOptimizedNonBooleanEqual(BlockScope currentScope, CodeStream codeStream, Label trueLabel, Label falseLabel, boolean valueRequired) { + + int pc = codeStream.position; + Constant inline; + if ((inline = right.constant) != NotAConstant) { + // optimized case: x == 0 + if (((left.implicitConversion >> 4) == T_int) && (inline.intValue() == 0)) { + left.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicit falling through the FALSE case + codeStream.ifeq(trueLabel); + } + } else { + // implicit falling through the TRUE case + if (trueLabel == null) { + codeStream.ifne(falseLabel); + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + } + if ((inline = left.constant) != NotAConstant) { + // optimized case: 0 == x + if (((left.implicitConversion >> 4) == T_int) + && (inline.intValue() == 0)) { + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicit falling through the FALSE case + codeStream.ifeq(trueLabel); + } + } else { + // implicit falling through the TRUE case + if (trueLabel == null) { + codeStream.ifne(falseLabel); + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + } + // null cases + // optimized case: x == null + if (right instanceof NullLiteral) { + if (left instanceof NullLiteral) { + // null == null + if (valueRequired) { + if ((bits & OnlyValueRequiredMASK) != 0) { + if (((bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) { + codeStream.iconst_1(); + } else { + codeStream.iconst_0(); + } + } else { + if (falseLabel == null) { + // implicit falling through the FALSE case + if (trueLabel != null) { + codeStream.goto_(trueLabel); + } + } + } + } + } else { + left.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicit falling through the FALSE case + codeStream.ifnull(trueLabel); + } + } else { + // implicit falling through the TRUE case + if (trueLabel == null) { + codeStream.ifnonnull(falseLabel); + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } else if (left instanceof NullLiteral) { // optimized case: null == x + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicit falling through the FALSE case + codeStream.ifnull(trueLabel); + } + } else { + // implicit falling through the TRUE case + if (trueLabel == null) { + codeStream.ifnonnull(falseLabel); + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + + // default case + left.generateCode(currentScope, codeStream, valueRequired); + right.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // implicit falling through the FALSE case + switch (left.implicitConversion >> 4) { // operand runtime type + case T_int : + codeStream.if_icmpeq(trueLabel); + break; + case T_float : + codeStream.fcmpl(); + codeStream.ifeq(trueLabel); + break; + case T_long : + codeStream.lcmp(); + codeStream.ifeq(trueLabel); + break; + case T_double : + codeStream.dcmpl(); + codeStream.ifeq(trueLabel); + break; + default : + codeStream.if_acmpeq(trueLabel); + } + } + } else { + // implicit falling through the TRUE case + if (trueLabel == null) { + switch (left.implicitConversion >> 4) { // operand runtime type + case T_int : + codeStream.if_icmpne(falseLabel); + break; + case T_float : + codeStream.fcmpl(); + codeStream.ifne(falseLabel); + break; + case T_long : + codeStream.lcmp(); + codeStream.ifne(falseLabel); + break; + case T_double : + codeStream.dcmpl(); + codeStream.ifne(falseLabel); + break; + default : + codeStream.if_acmpne(falseLabel); + } + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); +} +public boolean isCompactableOperation() { + return false; +} +public TypeBinding resolveType(BlockScope scope) { + + boolean leftIsCast, rightIsCast; + if ((leftIsCast = left instanceof CastExpression) == true) left.bits |= IgnoreNeedForCastCheckMASK; // will check later on + TypeBinding leftType = left.resolveType(scope); + + if ((rightIsCast = right instanceof CastExpression) == true) right.bits |= IgnoreNeedForCastCheckMASK; // will check later on + TypeBinding rightType = right.resolveType(scope); + + // always return BooleanBinding + if (leftType == null || rightType == null){ + constant = NotAConstant; + return null; + } + + // both base type + if (leftType.isBaseType() && rightType.isBaseType()) { + // the code is an int + // (cast) left == (cast) right --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 <<0 + int operatorSignature = OperatorSignatures[EQUAL_EQUAL][ (leftType.id << 4) + rightType.id]; + left.implicitConversion = operatorSignature >>> 12; + right.implicitConversion = (operatorSignature >>> 4) & 0x000FF; + bits |= operatorSignature & 0xF; + if ((operatorSignature & 0x0000F) == T_undefined) { + constant = Constant.NotAConstant; + scope.problemReporter().invalidOperator(this, leftType, rightType); + return null; + } + // check need for operand cast + if (leftIsCast || rightIsCast) { + CastExpression.checkNeedForArgumentCasts(scope, EQUAL_EQUAL, operatorSignature, left, leftType.id, leftIsCast, right, rightType.id, rightIsCast); + } + computeConstant(leftType, rightType); + return this.resolvedType = BooleanBinding; + } + + // Object references + // spec 15.20.3 + if (areTypesCastCompatible(scope, rightType, leftType) || areTypesCastCompatible(scope, leftType, rightType)) { + // (special case for String) + if ((rightType.id == T_String) && (leftType.id == T_String)) { + computeConstant(leftType, rightType); + } else { + constant = NotAConstant; + } + if (rightType.id == T_String) { + right.implicitConversion = String2String; + } + if (leftType.id == T_String) { + left.implicitConversion = String2String; + } + // check need for operand cast + boolean unnecessaryLeftCast = (left.bits & UnnecessaryCastMask) != 0; + boolean unnecessaryRightCast = (right.bits & UnnecessaryCastMask) != 0; + if (unnecessaryLeftCast || unnecessaryRightCast) { + TypeBinding alternateLeftType = unnecessaryLeftCast ? ((CastExpression)left).expression.resolvedType : leftType; + TypeBinding alternateRightType = unnecessaryRightCast ? ((CastExpression)right).expression.resolvedType : rightType; + if (areTypesCastCompatible(scope, alternateLeftType, alternateRightType) + || areTypesCastCompatible(scope, alternateRightType, alternateLeftType)) { + if (unnecessaryLeftCast) scope.problemReporter().unnecessaryCast((CastExpression)left); + if (unnecessaryRightCast) scope.problemReporter().unnecessaryCast((CastExpression)right); + } + } + return this.resolvedType = BooleanBinding; + } + constant = NotAConstant; + scope.problemReporter().notCompatibleTypesError(this, leftType, rightType); + return null; +} +public void traverse(ASTVisitor visitor, BlockScope scope) { + if (visitor.visit(this, scope)) { + left.traverse(visitor, scope); + right.traverse(visitor, scope); + } + visitor.endVisit(this, scope); +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java b/src/java/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java new file mode 100644 index 0000000..ec709ff --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java @@ -0,0 +1,340 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class ExplicitConstructorCall + extends Statement + implements InvocationSite { + + public Expression[] arguments; + public Expression qualification; + public MethodBinding binding; + + public int accessMode; + + public final static int ImplicitSuper = 1; + public final static int Super = 2; + public final static int This = 3; + + public VariableBinding[][] implicitArguments; + boolean discardEnclosingInstance; + + MethodBinding syntheticAccessor; + + public ExplicitConstructorCall(int accessMode) { + this.accessMode = accessMode; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + // must verify that exceptions potentially thrown by this expression are caught in the method. + + try { + ((MethodScope) currentScope).isConstructorCall = true; + + // process enclosing instance + if (qualification != null) { + flowInfo = + qualification + .analyseCode(currentScope, flowContext, flowInfo) + .unconditionalInits(); + } + // process arguments + if (arguments != null) { + for (int i = 0, max = arguments.length; i < max; i++) { + flowInfo = + arguments[i] + .analyseCode(currentScope, flowContext, flowInfo) + .unconditionalInits(); + } + } + + ReferenceBinding[] thrownExceptions; + if ((thrownExceptions = binding.thrownExceptions) != NoExceptions) { + // check exceptions + flowContext.checkExceptionHandlers( + thrownExceptions, + (accessMode == ImplicitSuper) + ? (ASTNode) currentScope.methodScope().referenceContext + : (ASTNode) this, + flowInfo, + currentScope); + } + manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo); + manageSyntheticAccessIfNecessary(currentScope, flowInfo); + return flowInfo; + } finally { + ((MethodScope) currentScope).isConstructorCall = false; + } + } + + /** + * Constructor call code generation + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + + if ((bits & IsReachableMASK) == 0) { + return; + } + try { + ((MethodScope) currentScope).isConstructorCall = true; + + int pc = codeStream.position; + codeStream.aload_0(); + + // handling innerclass constructor invocation + ReferenceBinding targetType = binding.declaringClass; + // handling innerclass instance allocation - enclosing instance arguments + if (targetType.isNestedType()) { + codeStream.generateSyntheticEnclosingInstanceValues( + currentScope, + targetType, + discardEnclosingInstance ? null : qualification, + this); + } + // regular code gen + if (arguments != null) { + for (int i = 0, max = arguments.length; i < max; i++) { + arguments[i].generateCode(currentScope, codeStream, true); + } + } + // handling innerclass instance allocation - outer local arguments + if (targetType.isNestedType()) { + codeStream.generateSyntheticOuterArgumentValues( + currentScope, + targetType, + this); + } + if (syntheticAccessor != null) { + // synthetic accessor got some extra arguments appended to its signature, which need values + for (int i = 0, + max = syntheticAccessor.parameters.length - binding.parameters.length; + i < max; + i++) { + codeStream.aconst_null(); + } + codeStream.invokespecial(syntheticAccessor); + } else { + codeStream.invokespecial(binding); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } finally { + ((MethodScope) currentScope).isConstructorCall = false; + } + } + + public boolean isImplicitSuper() { + //return true if I'm of these compiler added statement super(); + + return (accessMode == ImplicitSuper); + } + + public boolean isSuperAccess() { + + return accessMode != This; + } + + public boolean isTypeAccess() { + + return true; + } + + /* Inner emulation consists in either recording a dependency + * link only, or performing one level of propagation. + * + * Dependency mechanism is used whenever dealing with source target + * types, since by the time we reach them, we might not yet know their + * exact need. + */ + void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) { + ReferenceBinding superType; + + if (!flowInfo.isReachable()) return; + // perform some emulation work in case there is some and we are inside a local type only + if ((superType = binding.declaringClass).isNestedType() + && currentScope.enclosingSourceType().isLocalType()) { + + if (superType.isLocalType()) { + ((LocalTypeBinding) superType).addInnerEmulationDependent(currentScope, qualification != null); + } else { + // locally propagate, since we already now the desired shape for sure + currentScope.propagateInnerEmulation(superType, qualification != null); + } + } + } + + public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) { + + if (!flowInfo.isReachable()) return; + // perform some emulation work in case there is some and we are inside a local type only + if (binding.isPrivate() && (accessMode != This)) { + + if (currentScope + .environment() + .options + .isPrivateConstructorAccessChangingVisibility) { + binding.tagForClearingPrivateModifier(); + // constructor will not be dumped as private, no emulation required thus + } else { + syntheticAccessor = + ((SourceTypeBinding) binding.declaringClass).addSyntheticMethod(binding, isSuperAccess()); + currentScope.problemReporter().needToEmulateMethodAccess(binding, this); + } + } + } + + public StringBuffer printStatement(int indent, StringBuffer output) { + + printIndent(indent, output); + if (qualification != null) qualification.printExpression(0, output).append('.'); + if (accessMode == This) { + output.append("this("); //$NON-NLS-1$ + } else { + output.append("super("); //$NON-NLS-1$ + } + if (arguments != null) { + for (int i = 0; i < arguments.length; i++) { + if (i > 0) output.append(", "); //$NON-NLS-1$ + arguments[i].printExpression(0, output); + } + } + return output.append(");"); //$NON-NLS-1$ + } + + public void resolve(BlockScope scope) { + // the return type should be void for a constructor. + // the test is made into getConstructor + + // mark the fact that we are in a constructor call..... + // unmark at all returns + MethodScope methodScope = scope.methodScope(); + try { + AbstractMethodDeclaration methodDeclaration = methodScope.referenceMethod(); + if (methodDeclaration == null + || !methodDeclaration.isConstructor() + || ((ConstructorDeclaration) methodDeclaration).constructorCall != this) { + scope.problemReporter().invalidExplicitConstructorCall(this); + return; + } + methodScope.isConstructorCall = true; + ReferenceBinding receiverType = scope.enclosingSourceType(); + if (accessMode != This) + receiverType = receiverType.superclass(); + + if (receiverType == null) { + return; + } + + // qualification should be from the type of the enclosingType + if (qualification != null) { + if (accessMode != Super) { + scope.problemReporter().unnecessaryEnclosingInstanceSpecification( + qualification, + receiverType); + } + ReferenceBinding enclosingType = receiverType.enclosingType(); + if (enclosingType == null) { + scope.problemReporter().unnecessaryEnclosingInstanceSpecification( + qualification, + receiverType); + discardEnclosingInstance = true; + } else { + TypeBinding qTb = qualification.resolveTypeExpecting(scope, enclosingType); + qualification.implicitWidening(qTb, qTb); + } + } + + // arguments buffering for the method lookup + TypeBinding[] argumentTypes = NoParameters; + boolean argsContainCast = false; + if (arguments != null) { + boolean argHasError = false; // typeChecks all arguments + int length = arguments.length; + argumentTypes = new TypeBinding[length]; + for (int i = 0; i < length; i++) { + Expression argument = this.arguments[i]; + if (argument instanceof CastExpression) { + argument.bits |= IgnoreNeedForCastCheckMASK; // will check later on + argsContainCast = true; + } + if ((argumentTypes[i] = argument.resolveType(scope)) == null) { + argHasError = true; + } + } + if (argHasError) { + return; + } + } + if ((binding = scope.getConstructor(receiverType, argumentTypes, this)).isValidBinding()) { + if (isMethodUseDeprecated(binding, scope)) + scope.problemReporter().deprecatedMethod(binding, this); + + // see for user-implicit widening conversion + if (arguments != null) { + int length = arguments.length; + TypeBinding[] paramTypes = binding.parameters; + for (int i = 0; i < length; i++) { + arguments[i].implicitWidening(paramTypes[i], argumentTypes[i]); + } + if (argsContainCast) { + CastExpression.checkNeedForArgumentCasts(scope, null, receiverType, binding, this.arguments, argumentTypes, this); + } + } + if (binding.isPrivate()) { + binding.modifiers |= AccPrivateUsed; + } + } else { + if (binding.declaringClass == null) + binding.declaringClass = receiverType; + scope.problemReporter().invalidConstructor(this, binding); + } + } finally { + methodScope.isConstructorCall = false; + } + } + + public void setActualReceiverType(ReferenceBinding receiverType) { + // ignored + } + + public void setDepth(int depth) { + // ignore for here + } + + public void setFieldIndex(int depth) { + // ignore for here + } + + public void traverse(ASTVisitor visitor, BlockScope scope) { + + if (visitor.visit(this, scope)) { + if (this.qualification != null) { + this.qualification.traverse(visitor, scope); + } + if (this.arguments != null) { + for (int i = 0, argumentLength = this.arguments.length; i < argumentLength; i++) + this.arguments[i].traverse(visitor, scope); + } + } + visitor.endVisit(this, scope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/Expression.java b/src/java/org/eclipse/jdt/internal/compiler/ast/Expression.java new file mode 100644 index 0000000..ae3b502 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/Expression.java @@ -0,0 +1,496 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; +import org.eclipse.jdt.internal.compiler.problem.*; +import org.eclipse.jdt.internal.compiler.util.Util; + +public abstract class Expression extends Statement { + + //Some expression may not be used - from a java semantic point + //of view only - as statements. Other may. In order to avoid the creation + //of wrappers around expression in order to tune them as expression + //Expression is a subclass of Statement. See the message isValidJavaStatement() + + public int implicitConversion; + public TypeBinding resolvedType; + + public Constant constant; + + public Expression() { + super(); + } + + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + + return flowInfo; + } + + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { + + return analyseCode(currentScope, flowContext, flowInfo); + } + + /** + * Constant usable for bytecode pattern optimizations, but cannot be inlined + * since it is not strictly equivalent to the definition of constant expressions. + * In particular, some side-effects may be required to occur (only the end value + * is known). + * @return Constant known to be of boolean type + */ + public Constant optimizedBooleanConstant() { + return this.constant; + } + + public static final boolean isConstantValueRepresentable( + Constant constant, + int constantTypeID, + int targetTypeID) { + + //true if there is no loss of precision while casting. + // constantTypeID == constant.typeID + if (targetTypeID == constantTypeID) + return true; + switch (targetTypeID) { + case T_char : + switch (constantTypeID) { + case T_char : + return true; + case T_double : + return constant.doubleValue() == constant.charValue(); + case T_float : + return constant.floatValue() == constant.charValue(); + case T_int : + return constant.intValue() == constant.charValue(); + case T_short : + return constant.shortValue() == constant.charValue(); + case T_byte : + return constant.byteValue() == constant.charValue(); + case T_long : + return constant.longValue() == constant.charValue(); + default : + return false;//boolean + } + + case T_float : + switch (constantTypeID) { + case T_char : + return constant.charValue() == constant.floatValue(); + case T_double : + return constant.doubleValue() == constant.floatValue(); + case T_float : + return true; + case T_int : + return constant.intValue() == constant.floatValue(); + case T_short : + return constant.shortValue() == constant.floatValue(); + case T_byte : + return constant.byteValue() == constant.floatValue(); + case T_long : + return constant.longValue() == constant.floatValue(); + default : + return false;//boolean + } + + case T_double : + switch (constantTypeID) { + case T_char : + return constant.charValue() == constant.doubleValue(); + case T_double : + return true; + case T_float : + return constant.floatValue() == constant.doubleValue(); + case T_int : + return constant.intValue() == constant.doubleValue(); + case T_short : + return constant.shortValue() == constant.doubleValue(); + case T_byte : + return constant.byteValue() == constant.doubleValue(); + case T_long : + return constant.longValue() == constant.doubleValue(); + default : + return false; //boolean + } + + case T_byte : + switch (constantTypeID) { + case T_char : + return constant.charValue() == constant.byteValue(); + case T_double : + return constant.doubleValue() == constant.byteValue(); + case T_float : + return constant.floatValue() == constant.byteValue(); + case T_int : + return constant.intValue() == constant.byteValue(); + case T_short : + return constant.shortValue() == constant.byteValue(); + case T_byte : + return true; + case T_long : + return constant.longValue() == constant.byteValue(); + default : + return false; //boolean + } + + case T_short : + switch (constantTypeID) { + case T_char : + return constant.charValue() == constant.shortValue(); + case T_double : + return constant.doubleValue() == constant.shortValue(); + case T_float : + return constant.floatValue() == constant.shortValue(); + case T_int : + return constant.intValue() == constant.shortValue(); + case T_short : + return true; + case T_byte : + return constant.byteValue() == constant.shortValue(); + case T_long : + return constant.longValue() == constant.shortValue(); + default : + return false; //boolean + } + + case T_int : + switch (constantTypeID) { + case T_char : + return constant.charValue() == constant.intValue(); + case T_double : + return constant.doubleValue() == constant.intValue(); + case T_float : + return constant.floatValue() == constant.intValue(); + case T_int : + return true; + case T_short : + return constant.shortValue() == constant.intValue(); + case T_byte : + return constant.byteValue() == constant.intValue(); + case T_long : + return constant.longValue() == constant.intValue(); + default : + return false; //boolean + } + + case T_long : + switch (constantTypeID) { + case T_char : + return constant.charValue() == constant.longValue(); + case T_double : + return constant.doubleValue() == constant.longValue(); + case T_float : + return constant.floatValue() == constant.longValue(); + case T_int : + return constant.intValue() == constant.longValue(); + case T_short : + return constant.shortValue() == constant.longValue(); + case T_byte : + return constant.byteValue() == constant.longValue(); + case T_long : + return true; + default : + return false; //boolean + } + + default : + return false; //boolean + } + } + + /** + * Expression statements are plain expressions, however they generate like + * normal expressions with no value required. + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + + if ((bits & IsReachableMASK) == 0) { + return; + } + generateCode(currentScope, codeStream, false); + } + + /** + * Every expression is responsible for generating its implicit conversion when necessary. + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ + public void generateCode( + BlockScope currentScope, + CodeStream codeStream, + boolean valueRequired) { + + if (constant != NotAConstant) { + // generate a constant expression + int pc = codeStream.position; + codeStream.generateConstant(constant, implicitConversion); + codeStream.recordPositionsFrom(pc, this.sourceStart); + } else { + // actual non-constant code generation + throw new ShouldNotImplement(Util.bind("ast.missingCode")); //$NON-NLS-1$ + } + } + + /** + * Default generation of a boolean value + * @param currentScope + * @param codeStream + * @param trueLabel + * @param falseLabel + * @param valueRequired + */ + public void generateOptimizedBoolean( + BlockScope currentScope, + CodeStream codeStream, + Label trueLabel, + Label falseLabel, + boolean valueRequired) { + + // a label valued to nil means: by default we fall through the case... + // both nil means we leave the value on the stack + + if ((constant != Constant.NotAConstant) && (constant.typeID() == T_boolean)) { + int pc = codeStream.position; + if (constant.booleanValue() == true) { + // constant == true + if (valueRequired) { + if (falseLabel == null) { + // implicit falling through the FALSE case + if (trueLabel != null) { + codeStream.goto_(trueLabel); + } + } + } + } else { + if (valueRequired) { + if (falseLabel != null) { + // implicit falling through the TRUE case + if (trueLabel == null) { + codeStream.goto_(falseLabel); + } + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + generateCode(currentScope, codeStream, valueRequired); + // branching + int position = codeStream.position; + if (valueRequired) { + if (falseLabel == null) { + if (trueLabel != null) { + // Implicit falling through the FALSE case + codeStream.ifne(trueLabel); + } + } else { + if (trueLabel == null) { + // Implicit falling through the TRUE case + codeStream.ifeq(falseLabel); + } else { + // No implicit fall through TRUE/FALSE --> should never occur + } + } + } + // reposition the endPC + codeStream.updateLastRecordedEndPC(position); + } + + /* Optimized (java) code generation for string concatenations that involve StringBuffer + * creation: going through this path means that there is no need for a new StringBuffer + * creation, further operands should rather be only appended to the current one. + * By default: no optimization. + */ + public void generateOptimizedStringBuffer( + BlockScope blockScope, + org.eclipse.jdt.internal.compiler.codegen.CodeStream codeStream, + int typeID) { + + if (typeID == T_String && this.constant != NotAConstant && this.constant.stringValue().length() == 0) { + return; // optimize str + "" + } + generateCode(blockScope, codeStream, true); + codeStream.invokeStringBufferAppendForType(typeID); + } + + /* Optimized (java) code generation for string concatenations that involve StringBuffer + * creation: going through this path means that there is no need for a new StringBuffer + * creation, further operands should rather be only appended to the current one. + */ + public void generateOptimizedStringBufferCreation( + BlockScope blockScope, + CodeStream codeStream, + int typeID) { + + // Optimization only for integers and strings + if (typeID == T_Object) { + // in the case the runtime value of valueOf(Object) returns null, we have to use append(Object) instead of directly valueOf(Object) + // append(Object) returns append(valueOf(Object)), which means that the null case is handled by append(String). + codeStream.newStringBuffer(); + codeStream.dup(); + codeStream.invokeStringBufferDefaultConstructor(); + generateCode(blockScope, codeStream, true); + codeStream.invokeStringBufferAppendForType(T_Object); + return; + } + codeStream.newStringBuffer(); + codeStream.dup(); + if (typeID == T_String || typeID == T_null) { + if (constant != NotAConstant) { + String stringValue = constant.stringValue(); + if (stringValue.length() == 0) { // optimize ""+ + codeStream.invokeStringBufferDefaultConstructor(); + return; + } + codeStream.ldc(stringValue); + } else { + generateCode(blockScope, codeStream, true); + codeStream.invokeStringValueOf(T_Object); + } + } else { + generateCode(blockScope, codeStream, true); + codeStream.invokeStringValueOf(typeID); + } + codeStream.invokeStringBufferStringConstructor(); + } + + // Base types need that the widening is explicitly done by the compiler using some bytecode like i2f + public void implicitWidening( + TypeBinding runtimeTimeType, + TypeBinding compileTimeType) { + + if (runtimeTimeType == null || compileTimeType == null) + return; + +// if (compileTimeType.id == T_null) { +// // this case is possible only for constant null +// // The type of runtime is a reference type +// // The code gen use the constant id thus any value +// // for the runtime id (akak the <<4) could be used. +// // T_Object is used as some general T_reference +// implicitConversion = (T_Object << 4) + T_null; +// return; +// } + + switch (runtimeTimeType.id) { + case T_byte : + case T_short : + case T_char : + implicitConversion = (T_int << 4) + compileTimeType.id; + break; + case T_String : + case T_float : + case T_boolean : + case T_double : + case T_int : //implicitConversion may result in i2i which will result in NO code gen + case T_long : + implicitConversion = (runtimeTimeType.id << 4) + compileTimeType.id; + break; + default : //nothing on regular object ref + } + } + + public boolean isCompactableOperation() { + + return false; + } + + //Return true if the conversion is done AUTOMATICALLY by the vm + //while the javaVM is an int based-machine, thus for example pushing + //a byte onto the stack , will automatically creates a int on the stack + //(this request some work d be done by the VM on signed numbers) + public boolean isConstantValueOfTypeAssignableToType( + TypeBinding constantType, + TypeBinding targetType) { + + if (constant == Constant.NotAConstant) + return false; + if (constantType == targetType) + return true; + if (constantType.isBaseType() && targetType.isBaseType()) { + //No free assignment conversion from anything but to integral ones. + if ((constantType == IntBinding + || BaseTypeBinding.isWidening(T_int, constantType.id)) + && (BaseTypeBinding.isNarrowing(targetType.id, T_int))) { + //use current explicit conversion in order to get some new value to compare with current one + return isConstantValueRepresentable(constant, constantType.id, targetType.id); + } + } + return false; + } + + public boolean isTypeReference() { + return false; + } + + public void resolve(BlockScope scope) { + // drops the returning expression's type whatever the type is. + + this.resolveType(scope); + return; + } + + public TypeBinding resolveType(BlockScope scope) { + // by default... subclasses should implement a better TC if required. + + return null; + } + + public TypeBinding resolveType(ClassScope classScope) { + // by default... subclasses should implement a better TB if required. + return null; + } + + public TypeBinding resolveTypeExpecting( + BlockScope scope, + TypeBinding expectedType) { + + TypeBinding expressionType = this.resolveType(scope); + if (expressionType == null) return null; + if (expressionType == expectedType) return expressionType; + + if (!expressionType.isCompatibleWith(expectedType)) { + scope.problemReporter().typeMismatchError(expressionType, expectedType, this); + return null; + } + return expressionType; + } + + public StringBuffer print(int indent, StringBuffer output) { + printIndent(indent, output); + return printExpression(indent, output); + } + + public abstract StringBuffer printExpression(int indent, StringBuffer output); + + public StringBuffer printStatement(int indent, StringBuffer output) { + return print(indent, output).append(";"); //$NON-NLS-1$ + } + + public Expression toTypeReference() { + //by default undefined + + //this method is meanly used by the parser in order to transform + //an expression that is used as a type reference in a cast .... + //--appreciate the fact that castExpression and ExpressionWithParenthesis + //--starts with the same pattern..... + + return this; + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/ExtendedStringLiteral.java b/src/java/org/eclipse/jdt/internal/compiler/ast/ExtendedStringLiteral.java new file mode 100644 index 0000000..68b8fde --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/ExtendedStringLiteral.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.lookup.BlockScope; + +public class ExtendedStringLiteral extends StringLiteral { + + /** + * Build a string+char literal + */ + public ExtendedStringLiteral(StringLiteral str, CharLiteral character) { + + super(str.source, str.sourceStart, str.sourceEnd); + extendWith(character); + } + + /** + * Build a two-strings literal + * */ + public ExtendedStringLiteral(StringLiteral str1, StringLiteral str2) { + + super(str1.source, str1.sourceStart, str1.sourceEnd); + extendWith(str2); + } + + /** + * Add the lit source to mine, just as if it was mine + */ + public ExtendedStringLiteral extendWith(CharLiteral lit) { + + //update the source + int length = source.length; + System.arraycopy(source, 0, (source = new char[length + 1]), 0, length); + source[length] = lit.value; + //position at the end of all literals + sourceEnd = lit.sourceEnd; + return this; + } + + /** + * Add the lit source to mine, just as if it was mine + */ + public ExtendedStringLiteral extendWith(StringLiteral lit) { + + //uddate the source + int length = source.length; + System.arraycopy( + source, + 0, + source = new char[length + lit.source.length], + 0, + length); + System.arraycopy(lit.source, 0, source, length, lit.source.length); + //position at the end of all literals + sourceEnd = lit.sourceEnd; + return this; + } + + public StringBuffer printExpression(int indent, StringBuffer output) { + + return output.append("ExtendedStringLiteral{").append(source).append('}'); //$NON-NLS-1$ + } + + public void traverse(ASTVisitor visitor, BlockScope scope) { + + visitor.visit(this, scope); + visitor.endVisit(this, scope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/FalseLiteral.java b/src/java/org/eclipse/jdt/internal/compiler/ast/FalseLiteral.java new file mode 100644 index 0000000..82bc72d --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/FalseLiteral.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class FalseLiteral extends MagicLiteral { + static final char[] source = {'f', 'a', 'l', 's', 'e'}; +public FalseLiteral(int s , int e) { + super(s,e); +} +public void computeConstant() { + + constant = Constant.fromValue(false);} +/** + * Code generation for false literal + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ +public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { + int pc = codeStream.position; + if (valueRequired) + codeStream.iconst_0(); + codeStream.recordPositionsFrom(pc, this.sourceStart); +} +public void generateOptimizedBoolean(BlockScope currentScope, CodeStream codeStream, Label trueLabel, Label falseLabel, boolean valueRequired) { + + // falseLabel being not nil means that we will not fall through into the FALSE case + + int pc = codeStream.position; + if (valueRequired) { + if (falseLabel != null) { + // implicit falling through the TRUE case + if (trueLabel == null) { + codeStream.goto_(falseLabel); + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); +} +public TypeBinding literalType(BlockScope scope) { + return BooleanBinding; +} +/** + * + */ +public char[] source() { + return source; +} +public void traverse(ASTVisitor visitor, BlockScope scope) { + visitor.visit(this, scope); + visitor.endVisit(this, scope); +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java b/src/java/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java new file mode 100644 index 0000000..7f001c3 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java @@ -0,0 +1,253 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class FieldDeclaration extends AbstractVariableDeclaration { + public FieldBinding binding; + boolean hasBeenResolved = false; + public Javadoc javadoc; + + //allows to retrieve both the "type" part of the declaration (part1) + //and also the part that decribe the name and the init and optionally + //some other dimension ! .... + //public int[] a, b[] = X, c ; + //for b that would give for + // - part1 : public int[] + // - part2 : b[] = X, + + public int endPart1Position; + public int endPart2Position; + + public FieldDeclaration() { + // for subtypes or conversion + } + + public FieldDeclaration( + char[] name, + int sourceStart, + int sourceEnd) { + + this.name = name; + + //due to some declaration like + // int x, y = 3, z , x ; + //the sourceStart and the sourceEnd is ONLY on the name + this.sourceStart = sourceStart; + this.sourceEnd = sourceEnd; + } + + public FlowInfo analyseCode( + MethodScope initializationScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + if (this.binding != null && this.binding.isPrivate() && !this.binding.isPrivateUsed()) { + if (!initializationScope.referenceCompilationUnit().compilationResult.hasSyntaxError()) { + initializationScope.problemReporter().unusedPrivateField(this); + } + } + // cannot define static non-constant field inside nested class + if (this.binding != null + && this.binding.isValidBinding() + && this.binding.isStatic() + && this.binding.constant == NotAConstant + && this.binding.declaringClass.isNestedType() + && this.binding.declaringClass.isClass() + && !this.binding.declaringClass.isStatic()) { + initializationScope.problemReporter().unexpectedStaticModifierForField( + (SourceTypeBinding) this.binding.declaringClass, + this); + } + + if (this.initialization != null) { + flowInfo = + this.initialization + .analyseCode(initializationScope, flowContext, flowInfo) + .unconditionalInits(); + flowInfo.markAsDefinitelyAssigned(this.binding); + } + return flowInfo; + } + + /** + * Code generation for a field declaration: + * standard assignment to a field + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + + if ((this.bits & IsReachableMASK) == 0) { + return; + } + // do not generate initialization code if final and static (constant is then + // recorded inside the field itself). + int pc = codeStream.position; + boolean isStatic; + if (this.initialization != null + && !((isStatic = this.binding.isStatic()) && this.binding.constant != NotAConstant)) { + // non-static field, need receiver + if (!isStatic) + codeStream.aload_0(); + // generate initialization value + this.initialization.generateCode(currentScope, codeStream, true); + // store into field + if (isStatic) { + codeStream.putstatic(this.binding); + } else { + codeStream.putfield(this.binding); + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public TypeBinding getTypeBinding(Scope scope) { + + return this.type.getTypeBinding(scope); + } + + public boolean isField() { + + return true; + } + + public boolean isStatic() { + + if (this.binding != null) + return this.binding.isStatic(); + return (this.modifiers & AccStatic) != 0; + } + + public void resolve(MethodScope initializationScope) { + + // the two could be regrouped into + // a single line but it is clearer to have two lines while the reason of their + // existence is not at all the same. See comment for the second one. + + //-------------------------------------------------------- + if (!this.hasBeenResolved && this.binding != null && this.binding.isValidBinding()) { + + this.hasBeenResolved = true; + + // check if field is hiding some variable - issue is that field binding already got inserted in scope + // thus must lookup separately in super type and outer context + ClassScope classScope = initializationScope.enclosingClassScope(); + + if (classScope != null) { + SourceTypeBinding declaringType = classScope.enclosingSourceType(); + boolean checkLocal = true; + if (declaringType.superclass != null) { + Binding existingVariable = classScope.findField(declaringType.superclass, this.name, this, false /*do not resolve hidden field*/); + if (existingVariable != null && existingVariable.isValidBinding()){ + initializationScope.problemReporter().fieldHiding(this, existingVariable); + checkLocal = false; // already found a matching field + } + } + if (checkLocal) { + Scope outerScope = classScope.parent; + // only corner case is: lookup of outer field through static declaringType, which isn't detected by #getBinding as lookup starts + // from outer scope. Subsequent static contexts are detected for free. + Binding existingVariable = outerScope.getBinding(this.name, BindingIds.VARIABLE, this, false /*do not resolve hidden field*/); + if (existingVariable != null && existingVariable.isValidBinding() + && (!(existingVariable instanceof FieldBinding) + || ((FieldBinding) existingVariable).isStatic() + || !declaringType.isStatic())) { + initializationScope.problemReporter().fieldHiding(this, existingVariable); + } + } + } + + this.type.resolvedType = this.binding.type; // update binding for type reference + + FieldBinding previousField = initializationScope.initializedField; + int previousFieldID = initializationScope.lastVisibleFieldID; + try { + initializationScope.initializedField = this.binding; + initializationScope.lastVisibleFieldID = this.binding.id; + + if (isTypeUseDeprecated(this.binding.type, initializationScope)) { + initializationScope.problemReporter().deprecatedType(this.binding.type, this.type); + } + // the resolution of the initialization hasn't been done + if (this.initialization == null) { + this.binding.constant = Constant.NotAConstant; + } else { + // break dead-lock cycles by forcing constant to NotAConstant + this.binding.constant = Constant.NotAConstant; + + TypeBinding typeBinding = this.binding.type; + TypeBinding initializationTypeBinding; + + if (this.initialization instanceof ArrayInitializer) { + + if ((initializationTypeBinding = this.initialization.resolveTypeExpecting(initializationScope, typeBinding)) != null) { + ((ArrayInitializer) this.initialization).binding = (ArrayBinding) initializationTypeBinding; + this.initialization.implicitWidening(typeBinding, initializationTypeBinding); + } + } else if ((initializationTypeBinding = this.initialization.resolveType(initializationScope)) != null) { + + if (this.initialization.isConstantValueOfTypeAssignableToType(initializationTypeBinding, typeBinding) + || (typeBinding.isBaseType() && BaseTypeBinding.isWidening(typeBinding.id, initializationTypeBinding.id))) { + + this.initialization.implicitWidening(typeBinding, initializationTypeBinding); + + } else if (initializationTypeBinding.isCompatibleWith(typeBinding)) { + this.initialization.implicitWidening(typeBinding, initializationTypeBinding); + + } else { + initializationScope.problemReporter().typeMismatchError(initializationTypeBinding, typeBinding, this); + } + if (this.binding.isFinal()){ // cast from constant actual type to variable type + this.binding.constant = + this.initialization.constant.castTo( + (this.binding.type.id << 4) + this.initialization.constant.typeID()); + } + } else { + this.binding.constant = NotAConstant; + } + } + // Resolve Javadoc comment if one is present + if (this.javadoc != null) { + /* + if (classScope != null) { + this.javadoc.resolve(classScope); + } + */ + this.javadoc.resolve(initializationScope); + } else if (this.binding != null && this.binding.declaringClass != null && !this.binding.declaringClass.isLocalType()) { + initializationScope.problemReporter().javadocMissing(this.sourceStart, this.sourceEnd, this.binding.modifiers); + } + } finally { + initializationScope.initializedField = previousField; + initializationScope.lastVisibleFieldID = previousFieldID; + if (this.binding.constant == null) + this.binding.constant = Constant.NotAConstant; + } + } + } + + public void traverse(ASTVisitor visitor, MethodScope scope) { + + if (visitor.visit(this, scope)) { + this.type.traverse(visitor, scope); + if (this.initialization != null) + this.initialization.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/FieldReference.java b/src/java/org/eclipse/jdt/internal/compiler/ast/FieldReference.java new file mode 100644 index 0000000..9c4a86d --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/FieldReference.java @@ -0,0 +1,559 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class FieldReference extends Reference implements InvocationSite { + + public Expression receiver; + public char[] token; + public FieldBinding binding, codegenBinding; + public long nameSourcePosition; //(start<<32)+end + MethodBinding syntheticReadAccessor, syntheticWriteAccessor; + public TypeBinding receiverType; + + public FieldReference(char[] source, long pos) { + + token = source; + nameSourcePosition = pos; + //by default the position are the one of the field (not true for super access) + sourceStart = (int) (pos >>> 32); + sourceEnd = (int) (pos & 0x00000000FFFFFFFFL); + bits |= BindingIds.FIELD; + + } + + public FlowInfo analyseAssignment( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo, + Assignment assignment, + boolean isCompound) { + + // compound assignment extra work + if (isCompound) { // check the variable part is initialized if blank final + if (binding.isBlankFinal() + && receiver.isThis() + && currentScope.allowBlankFinalFieldAssignment(binding) + && (!flowInfo.isDefinitelyAssigned(binding))) { + currentScope.problemReporter().uninitializedBlankFinalField(binding, this); + // we could improve error msg here telling "cannot use compound assignment on final blank field" + } + manageSyntheticReadAccessIfNecessary(currentScope, flowInfo); + } + flowInfo = + receiver + .analyseCode(currentScope, flowContext, flowInfo, !binding.isStatic()) + .unconditionalInits(); + if (assignment.expression != null) { + flowInfo = + assignment + .expression + .analyseCode(currentScope, flowContext, flowInfo) + .unconditionalInits(); + } + manageSyntheticWriteAccessIfNecessary(currentScope, flowInfo); + + // check if assigning a final field + if (binding.isFinal()) { + // in a context where it can be assigned? + if (binding.isBlankFinal() + && !isCompound + && receiver.isThis() + && !(receiver instanceof QualifiedThisReference) + && ((receiver.bits & ParenthesizedMASK) == 0) // (this).x is forbidden + && currentScope.allowBlankFinalFieldAssignment(binding)) { + if (flowInfo.isPotentiallyAssigned(binding)) { + currentScope.problemReporter().duplicateInitializationOfBlankFinalField( + binding, + this); + } else { + flowContext.recordSettingFinal(binding, this, flowInfo); + } + flowInfo.markAsDefinitelyAssigned(binding); + } else { + // assigning a final field outside an initializer or constructor or wrong reference + currentScope.problemReporter().cannotAssignToFinalField(binding, this); + } + } + return flowInfo; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + return analyseCode(currentScope, flowContext, flowInfo, true); + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo, + boolean valueRequired) { + + receiver.analyseCode(currentScope, flowContext, flowInfo, !binding.isStatic()); + if (valueRequired) { + manageSyntheticReadAccessIfNecessary(currentScope, flowInfo); + } + return flowInfo; + } + + public FieldBinding fieldBinding() { + + return binding; + } + + public void generateAssignment( + BlockScope currentScope, + CodeStream codeStream, + Assignment assignment, + boolean valueRequired) { + + receiver.generateCode( + currentScope, + codeStream, + !this.codegenBinding.isStatic()); + assignment.expression.generateCode(currentScope, codeStream, true); + fieldStore( + codeStream, + this.codegenBinding, + syntheticWriteAccessor, + valueRequired); + if (valueRequired) { + codeStream.generateImplicitConversion(assignment.implicitConversion); + } + } + + /** + * Field reference code generation + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ + public void generateCode( + BlockScope currentScope, + CodeStream codeStream, + boolean valueRequired) { + + int pc = codeStream.position; + if (constant != NotAConstant) { + if (valueRequired) { + codeStream.generateConstant(constant, implicitConversion); + } + } else { + boolean isStatic = this.codegenBinding.isStatic(); + receiver.generateCode(currentScope, codeStream, !isStatic); + if (valueRequired) { + if (this.codegenBinding.constant == NotAConstant) { + if (this.codegenBinding.declaringClass == null) { // array length + codeStream.arraylength(); + } else { + if (syntheticReadAccessor == null) { + if (isStatic) { + codeStream.getstatic(this.codegenBinding); + } else { + codeStream.getfield(this.codegenBinding); + } + } else { + codeStream.invokestatic(syntheticReadAccessor); + } + } + codeStream.generateImplicitConversion(implicitConversion); + } else { + if (!isStatic) { + codeStream.invokeObjectGetClass(); // perform null check + codeStream.pop(); + } + codeStream.generateConstant(this.codegenBinding.constant, implicitConversion); + } + } else { + if (!isStatic){ + codeStream.invokeObjectGetClass(); // perform null check + codeStream.pop(); + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public void generateCompoundAssignment( + BlockScope currentScope, + CodeStream codeStream, + Expression expression, + int operator, + int assignmentImplicitConversion, + boolean valueRequired) { + + boolean isStatic; + receiver.generateCode( + currentScope, + codeStream, + !(isStatic = this.codegenBinding.isStatic())); + if (isStatic) { + if (syntheticReadAccessor == null) { + codeStream.getstatic(this.codegenBinding); + } else { + codeStream.invokestatic(syntheticReadAccessor); + } + } else { + codeStream.dup(); + if (syntheticReadAccessor == null) { + codeStream.getfield(this.codegenBinding); + } else { + codeStream.invokestatic(syntheticReadAccessor); + } + } + int operationTypeID; + if ((operationTypeID = implicitConversion >> 4) == T_String) { + codeStream.generateStringAppend(currentScope, null, expression); + } else { + // promote the array reference to the suitable operation type + codeStream.generateImplicitConversion(implicitConversion); + // generate the increment value (will by itself be promoted to the operation value) + if (expression == IntLiteral.One) { // prefix operation + codeStream.generateConstant(expression.constant, implicitConversion); + } else { + expression.generateCode(currentScope, codeStream, true); + } + // perform the operation + codeStream.sendOperator(operator, operationTypeID); + // cast the value back to the array reference type + codeStream.generateImplicitConversion(assignmentImplicitConversion); + } + fieldStore( + codeStream, + this.codegenBinding, + syntheticWriteAccessor, + valueRequired); + } + + public void generatePostIncrement( + BlockScope currentScope, + CodeStream codeStream, + CompoundAssignment postIncrement, + boolean valueRequired) { + + boolean isStatic; + receiver.generateCode( + currentScope, + codeStream, + !(isStatic = this.codegenBinding.isStatic())); + if (isStatic) { + if (syntheticReadAccessor == null) { + codeStream.getstatic(this.codegenBinding); + } else { + codeStream.invokestatic(syntheticReadAccessor); + } + } else { + codeStream.dup(); + if (syntheticReadAccessor == null) { + codeStream.getfield(this.codegenBinding); + } else { + codeStream.invokestatic(syntheticReadAccessor); + } + } + if (valueRequired) { + if (isStatic) { + if ((this.codegenBinding.type == LongBinding) + || (this.codegenBinding.type == DoubleBinding)) { + codeStream.dup2(); + } else { + codeStream.dup(); + } + } else { // Stack: [owner][old field value] ---> [old field value][owner][old field value] + if ((this.codegenBinding.type == LongBinding) + || (this.codegenBinding.type == DoubleBinding)) { + codeStream.dup2_x1(); + } else { + codeStream.dup_x1(); + } + } + } + codeStream.generateConstant( + postIncrement.expression.constant, + implicitConversion); + codeStream.sendOperator(postIncrement.operator, this.codegenBinding.type.id); + codeStream.generateImplicitConversion( + postIncrement.assignmentImplicitConversion); + fieldStore(codeStream, this.codegenBinding, syntheticWriteAccessor, false); + } + + public static final Constant getConstantFor( + FieldBinding binding, + Reference reference, + boolean isImplicit, + Scope referenceScope) { + + //propagation of the constant. + + //ref can be a FieldReference, a SingleNameReference or a QualifiedNameReference + //indexInQualification may have a value greater than zero only for QualifiednameReference + //if ref==null then indexInQualification==0 AND implicitReceiver == false. This case is a + //degenerated case where a fake reference field (null) + //is associted to a real FieldBinding in order + //to allow its constant computation using the regular path (in other words, find the fieldDeclaration + //and proceed to its type resolution). As implicitReceiver is false, no error reporting + //against ref will be used ==> no nullPointerException risk .... + + //special treatment for langage-built-in field (their declaring class is null) + if (binding.declaringClass == null) { + //currently only one field "length" : the constant computation is never done + return NotAConstant; + } + if (!binding.isFinal()) { + return binding.constant = NotAConstant; + } + if (binding.constant != null) { + if (isImplicit || (reference instanceof QualifiedNameReference + && binding == ((QualifiedNameReference)reference).binding)) { + return binding.constant; + } + return NotAConstant; + } + + //The field has not been yet type checked. + //It also means that the field is not coming from a class that + //has already been compiled. It can only be from a class within + //compilation units to process. Thus the field is NOT from a BinaryTypeBinbing + + SourceTypeBinding typeBinding = (SourceTypeBinding) binding.declaringClass; + TypeDeclaration typeDecl = typeBinding.scope.referenceContext; + FieldDeclaration fieldDecl = typeDecl.declarationOf(binding); + + fieldDecl.resolve(binding.isStatic() //side effect on binding + ? typeDecl.staticInitializerScope + : typeDecl.initializerScope); + + if (isImplicit || (reference instanceof QualifiedNameReference + && binding == ((QualifiedNameReference)reference).binding)) { + return binding.constant; + } + return NotAConstant; + } + + public boolean isSuperAccess() { + + return receiver.isSuper(); + } + + public boolean isTypeAccess() { + + return receiver != null && receiver.isTypeReference(); + } + + /* + * No need to emulate access to protected fields since not implicitly accessed + */ + public void manageSyntheticReadAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) { + + if (!flowInfo.isReachable()) return; + if (binding.isPrivate()) { + if ((currentScope.enclosingSourceType() != binding.declaringClass) + && (binding.constant == NotAConstant)) { + syntheticReadAccessor = + ((SourceTypeBinding) binding.declaringClass).addSyntheticMethod(binding, true); + currentScope.problemReporter().needToEmulateFieldReadAccess(binding, this); + return; + } + + } else if (receiver instanceof QualifiedSuperReference) { // qualified super + + // qualified super need emulation always + SourceTypeBinding destinationType = + (SourceTypeBinding) (((QualifiedSuperReference) receiver) + .currentCompatibleType); + syntheticReadAccessor = destinationType.addSyntheticMethod(binding, true); + currentScope.problemReporter().needToEmulateFieldReadAccess(binding, this); + return; + + } else if (binding.isProtected()) { + + SourceTypeBinding enclosingSourceType; + if (((bits & DepthMASK) != 0) + && binding.declaringClass.getPackage() + != (enclosingSourceType = currentScope.enclosingSourceType()).getPackage()) { + + SourceTypeBinding currentCompatibleType = + (SourceTypeBinding) enclosingSourceType.enclosingTypeAt( + (bits & DepthMASK) >> DepthSHIFT); + syntheticReadAccessor = currentCompatibleType.addSyntheticMethod(binding, true); + currentScope.problemReporter().needToEmulateFieldReadAccess(binding, this); + return; + } + } + // if the binding declaring class is not visible, need special action + // for runtime compatibility on 1.2 VMs : change the declaring class of the binding + // NOTE: from target 1.2 on, field's declaring class is touched if any different from receiver type + if (binding.declaringClass != this.receiverType + && !this.receiverType.isArrayType() + && binding.declaringClass != null // array.length + && binding.constant == NotAConstant + && ((currentScope.environment().options.targetJDK >= ClassFileConstants.JDK1_2 + && binding.declaringClass.id != T_Object) + //no change for Object fields (in case there was) + || !binding.declaringClass.canBeSeenBy(currentScope))) { + this.codegenBinding = + currentScope.enclosingSourceType().getUpdatedFieldBinding( + binding, + (ReferenceBinding) this.receiverType); + } + } + + /* + * No need to emulate access to protected fields since not implicitly accessed + */ + public void manageSyntheticWriteAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) { + + if (!flowInfo.isReachable()) return; + if (binding.isPrivate()) { + if (currentScope.enclosingSourceType() != binding.declaringClass) { + syntheticWriteAccessor = + ((SourceTypeBinding) binding.declaringClass).addSyntheticMethod(binding, false); + currentScope.problemReporter().needToEmulateFieldWriteAccess(binding, this); + return; + } + + } else if (receiver instanceof QualifiedSuperReference) { // qualified super + + // qualified super need emulation always + SourceTypeBinding destinationType = + (SourceTypeBinding) (((QualifiedSuperReference) receiver) + .currentCompatibleType); + syntheticWriteAccessor = destinationType.addSyntheticMethod(binding, false); + currentScope.problemReporter().needToEmulateFieldWriteAccess(binding, this); + return; + + } else if (binding.isProtected()) { + + SourceTypeBinding enclosingSourceType; + if (((bits & DepthMASK) != 0) + && binding.declaringClass.getPackage() + != (enclosingSourceType = currentScope.enclosingSourceType()).getPackage()) { + + SourceTypeBinding currentCompatibleType = + (SourceTypeBinding) enclosingSourceType.enclosingTypeAt( + (bits & DepthMASK) >> DepthSHIFT); + syntheticWriteAccessor = + currentCompatibleType.addSyntheticMethod(binding, false); + currentScope.problemReporter().needToEmulateFieldWriteAccess(binding, this); + return; + } + } + // if the binding declaring class is not visible, need special action + // for runtime compatibility on 1.2 VMs : change the declaring class of the binding + // NOTE: from target 1.2 on, field's declaring class is touched if any different from receiver type + if (binding.declaringClass != this.receiverType + && !this.receiverType.isArrayType() + && binding.declaringClass != null // array.length + && binding.constant == NotAConstant + && ((currentScope.environment().options.targetJDK >= ClassFileConstants.JDK1_2 + && binding.declaringClass.id != T_Object) + //no change for Object fields (in case there was) + || !binding.declaringClass.canBeSeenBy(currentScope))) { + this.codegenBinding = + currentScope.enclosingSourceType().getUpdatedFieldBinding( + binding, + (ReferenceBinding) this.receiverType); + } + } + + public StringBuffer printExpression(int indent, StringBuffer output) { + + return receiver.printExpression(0, output).append('.').append(token); + } + + public TypeBinding resolveType(BlockScope scope) { + + // Answer the signature type of the field. + // constants are propaged when the field is final + // and initialized with a (compile time) constant + + //always ignore receiver cast, since may affect constant pool reference + boolean receiverCast = false; + if (this.receiver instanceof CastExpression) { + this.receiver.bits |= IgnoreNeedForCastCheckMASK; // will check later on + receiverCast = true; + } + this.receiverType = receiver.resolveType(scope); + if (this.receiverType == null) { + constant = NotAConstant; + return null; + } + if (receiverCast) { + // due to change of declaring class with receiver type, only identity cast should be notified + if (((CastExpression)this.receiver).expression.resolvedType == this.receiverType) { + scope.problemReporter().unnecessaryCast((CastExpression)this.receiver); + } + } + // the case receiverType.isArrayType and token = 'length' is handled by the scope API + this.codegenBinding = this.binding = scope.getField(this.receiverType, token, this); + if (!binding.isValidBinding()) { + constant = NotAConstant; + scope.problemReporter().invalidField(this, this.receiverType); + return null; + } + + if (isFieldUseDeprecated(binding, scope, (this.bits & IsStrictlyAssignedMASK) !=0)) { + scope.problemReporter().deprecatedField(binding, this); + } + boolean isImplicitThisRcv = receiver.isImplicitThis(); + constant = FieldReference.getConstantFor(binding, this, isImplicitThisRcv, scope); + if (!isImplicitThisRcv) { + constant = NotAConstant; + } + if (binding.isStatic()) { + // static field accessed through receiver? legal but unoptimal (optional warning) + if (!(isImplicitThisRcv + || receiver.isSuper() + || (receiver instanceof NameReference + && (((NameReference) receiver).bits & BindingIds.TYPE) != 0))) { + scope.problemReporter().nonStaticAccessToStaticField(this, binding); + } + if (!isImplicitThisRcv && binding.declaringClass != receiverType) { + scope.problemReporter().indirectAccessToStaticField(this, binding); + } + } + return this.resolvedType = binding.type; + } + + public void setActualReceiverType(ReferenceBinding receiverType) { + // ignored + } + + public void setDepth(int depth) { + + bits &= ~DepthMASK; // flush previous depth if any + if (depth > 0) { + bits |= (depth & 0xFF) << DepthSHIFT; // encoded on 8 bits + } + } + + public void setFieldIndex(int index) { + // ignored + } + + public void traverse(ASTVisitor visitor, BlockScope scope) { + + if (visitor.visit(this, scope)) { + receiver.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/FloatLiteral.java b/src/java/org/eclipse/jdt/internal/compiler/ast/FloatLiteral.java new file mode 100644 index 0000000..c7d53d6 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/FloatLiteral.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class FloatLiteral extends NumberLiteral { + float value; + final static float Float_MIN_VALUE = Float.intBitsToFloat(1); // work-around VAJ problem 1F6IGUU +public FloatLiteral(char[] token, int s, int e) { + super(token, s,e); +} +public void computeConstant() { + + //the source is correctly formated so the exception should never occurs + + Float computedValue; + try { + computedValue = Float.valueOf(String.valueOf(source)); + } catch (NumberFormatException e) { + return; + } + + if (computedValue.doubleValue() > Float.MAX_VALUE){ + return; //may be Infinity + } + if (computedValue.floatValue() < Float_MIN_VALUE){ + // see 1F6IGUU + //only a true 0 can be made of zeros + //1.00000000e-46f is illegal .... + label : for (int i = 0; i < source.length; i++) { + switch (source[i]) { + case '.' : + case 'f' : + case 'F' : + case '0' : + break; + case 'e' : + case 'E' : + break label; //exposant are valid !.... + default : + return; //error + } + } + } + constant = Constant.fromValue(value = computedValue.floatValue()); +} +/** + * Code generation for float literal + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ +public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { + int pc = codeStream.position; + if (valueRequired) + if ((implicitConversion >> 4) == T_float) + codeStream.generateInlinedValue(value); + else + codeStream.generateConstant(constant, implicitConversion); + codeStream.recordPositionsFrom(pc, this.sourceStart); +} +public TypeBinding literalType(BlockScope scope) { + return FloatBinding; +} +public void traverse(ASTVisitor visitor, BlockScope blockScope) { + visitor.visit(this, blockScope); + visitor.endVisit(this, blockScope); +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/ForStatement.java b/src/java/org/eclipse/jdt/internal/compiler/ast/ForStatement.java new file mode 100644 index 0000000..51c5db6 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/ForStatement.java @@ -0,0 +1,327 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.impl.Constant; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class ForStatement extends Statement { + + public Statement[] initializations; + public Expression condition; + public Statement[] increments; + public Statement action; + + //when there is no local declaration, there is no need of a new scope + //scope is positionned either to a new scope, or to the "upper"scope (see resolveType) + public boolean neededScope; + public BlockScope scope; + + private Label breakLabel, continueLabel; + + // for local variables table attributes + int preCondInitStateIndex = -1; + int condIfTrueInitStateIndex = -1; + int mergedInitStateIndex = -1; + + public ForStatement( + Statement[] initializations, + Expression condition, + Statement[] increments, + Statement action, + boolean neededScope, + int s, + int e) { + + this.sourceStart = s; + this.sourceEnd = e; + this.initializations = initializations; + this.condition = condition; + this.increments = increments; + this.action = action; + // remember useful empty statement + if (action instanceof EmptyStatement) action.bits |= IsUsefulEmptyStatementMASK; + this.neededScope = neededScope; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + breakLabel = new Label(); + continueLabel = new Label(); + + // process the initializations + if (initializations != null) { + for (int i = 0, count = initializations.length; i < count; i++) { + flowInfo = initializations[i].analyseCode(scope, flowContext, flowInfo); + } + } + preCondInitStateIndex = + currentScope.methodScope().recordInitializationStates(flowInfo); + + Constant cst = this.condition == null ? null : this.condition.constant; + boolean isConditionTrue = cst == null || (cst != NotAConstant && cst.booleanValue() == true); + boolean isConditionFalse = cst != null && (cst != NotAConstant && cst.booleanValue() == false); + + cst = this.condition == null ? null : this.condition.optimizedBooleanConstant(); + boolean isConditionOptimizedTrue = cst == null || (cst != NotAConstant && cst.booleanValue() == true); + boolean isConditionOptimizedFalse = cst != null && (cst != NotAConstant && cst.booleanValue() == false); + + // process the condition + LoopingFlowContext condLoopContext = null; + if (condition != null) { + if (!isConditionTrue) { + flowInfo = + condition.analyseCode( + scope, + (condLoopContext = + new LoopingFlowContext(flowContext, this, null, null, scope)), + flowInfo); + } + } + + // process the action + LoopingFlowContext loopingContext; + FlowInfo actionInfo; + if (action == null + || (action.isEmptyBlock() && currentScope.environment().options.complianceLevel <= ClassFileConstants.JDK1_3)) { + if (condLoopContext != null) + condLoopContext.complainOnFinalAssignmentsInLoop(scope, flowInfo); + if (isConditionTrue) { + return FlowInfo.DEAD_END; + } else { + if (isConditionFalse){ + continueLabel = null; // for(;false;p()); + } + actionInfo = flowInfo.initsWhenTrue().copy(); + loopingContext = + new LoopingFlowContext(flowContext, this, breakLabel, continueLabel, scope); + } + } else { + loopingContext = + new LoopingFlowContext(flowContext, this, breakLabel, continueLabel, scope); + FlowInfo initsWhenTrue = flowInfo.initsWhenTrue(); + condIfTrueInitStateIndex = + currentScope.methodScope().recordInitializationStates(initsWhenTrue); + + if (isConditionFalse) { + actionInfo = FlowInfo.DEAD_END; + } else { + actionInfo = initsWhenTrue.copy(); + if (isConditionOptimizedFalse){ + actionInfo.setReachMode(FlowInfo.UNREACHABLE); + } + } + if (!this.action.complainIfUnreachable(actionInfo, scope, false)) { + actionInfo = action.analyseCode(scope, loopingContext, actionInfo); + } + + // code generation can be optimized when no need to continue in the loop + if (!actionInfo.isReachable() && !loopingContext.initsOnContinue.isReachable()) { + continueLabel = null; + } else { + if (condLoopContext != null) + condLoopContext.complainOnFinalAssignmentsInLoop(scope, flowInfo); + actionInfo = actionInfo.mergedWith(loopingContext.initsOnContinue.unconditionalInits()); + loopingContext.complainOnFinalAssignmentsInLoop(scope, actionInfo); + } + } + // for increments + if ((continueLabel != null) && (increments != null)) { + LoopingFlowContext loopContext = + new LoopingFlowContext(flowContext, this, null, null, scope); + for (int i = 0, count = increments.length; i < count; i++) { + actionInfo = increments[i].analyseCode(scope, loopContext, actionInfo); + } + loopContext.complainOnFinalAssignmentsInLoop(scope, actionInfo); + } + + //end of loop + FlowInfo mergedInfo = FlowInfo.mergedOptimizedBranches( + loopingContext.initsOnBreak, + isConditionOptimizedTrue, + flowInfo.initsWhenFalse(), + isConditionOptimizedFalse, + !isConditionTrue /*for(;;){}while(true); unreachable(); */); + mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo); + return mergedInfo; + } + + /** + * For statement code generation + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + + if ((bits & IsReachableMASK) == 0) { + return; + } + int pc = codeStream.position; + + // generate the initializations + if (initializations != null) { + for (int i = 0, max = initializations.length; i < max; i++) { + initializations[i].generateCode(scope, codeStream); + } + } + + // label management + Label actionLabel = new Label(codeStream); + Label conditionLabel = new Label(codeStream); + breakLabel.initialize(codeStream); + if (continueLabel != null) { + continueLabel.initialize(codeStream); + } + // jump over the actionBlock + if ((condition != null) + && (condition.constant == NotAConstant) + && !((action == null || action.isEmptyBlock()) && (increments == null))) { + int jumpPC = codeStream.position; + codeStream.goto_(conditionLabel); + codeStream.recordPositionsFrom(jumpPC, condition.sourceStart); + } + // generate the loop action + actionLabel.place(); + if (action != null) { + // Required to fix 1PR0XVS: LFRE:WINNT - Compiler: variable table for method appears incorrect + if (condIfTrueInitStateIndex != -1) { + // insert all locals initialized inside the condition into the action generated prior to the condition + codeStream.addDefinitelyAssignedVariables( + currentScope, + condIfTrueInitStateIndex); + } + action.generateCode(scope, codeStream); + } + // continuation point + if (continueLabel != null) { + continueLabel.place(); + // generate the increments for next iteration + if (increments != null) { + for (int i = 0, max = increments.length; i < max; i++) { + increments[i].generateCode(scope, codeStream); + } + } + } + + // May loose some local variable initializations : affecting the local variable attributes + if (preCondInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + preCondInitStateIndex); + } + + // generate the condition + conditionLabel.place(); + if ((condition != null) && (condition.constant == NotAConstant)) { + condition.generateOptimizedBoolean(scope, codeStream, actionLabel, null, true); + } else { + if (continueLabel != null) { + codeStream.goto_(actionLabel); + } + } + breakLabel.place(); + + // May loose some local variable initializations : affecting the local variable attributes + if (neededScope) { + codeStream.exitUserScope(scope); + } + if (mergedInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables(currentScope, mergedInitStateIndex); + codeStream.addDefinitelyAssignedVariables(currentScope, mergedInitStateIndex); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public StringBuffer printStatement(int tab, StringBuffer output) { + + printIndent(tab, output).append("for ("); //$NON-NLS-1$ + //inits + if (initializations != null) { + for (int i = 0; i < initializations.length; i++) { + //nice only with expressions + if (i > 0) output.append(", "); //$NON-NLS-1$ + initializations[i].print(0, output); + } + } + output.append("; "); //$NON-NLS-1$ + //cond + if (condition != null) condition.printExpression(0, output); + output.append("; "); //$NON-NLS-1$ + //updates + if (increments != null) { + for (int i = 0; i < increments.length; i++) { + if (i > 0) output.append(", "); //$NON-NLS-1$ + increments[i].print(0, output); + } + } + output.append(") "); //$NON-NLS-1$ + //block + if (action == null) + output.append(';'); + else { + output.append('\n'); + action.printStatement(tab + 1, output); //$NON-NLS-1$ + } + return output.append(';'); + } + + public void resolve(BlockScope upperScope) { + + // use the scope that will hold the init declarations + scope = neededScope ? new BlockScope(upperScope) : upperScope; + if (initializations != null) + for (int i = 0, length = initializations.length; i < length; i++) + initializations[i].resolve(scope); + if (condition != null) { + TypeBinding type = condition.resolveTypeExpecting(scope, BooleanBinding); + condition.implicitWidening(type, type); + } + if (increments != null) + for (int i = 0, length = increments.length; i < length; i++) + increments[i].resolve(scope); + if (action != null) + action.resolve(scope); + } + + public void traverse( + ASTVisitor visitor, + BlockScope blockScope) { + + if (visitor.visit(this, blockScope)) { + if (initializations != null) { + int initializationsLength = initializations.length; + for (int i = 0; i < initializationsLength; i++) + initializations[i].traverse(visitor, scope); + } + + if (condition != null) + condition.traverse(visitor, scope); + + if (increments != null) { + int incrementsLength = increments.length; + for (int i = 0; i < incrementsLength; i++) + increments[i].traverse(visitor, scope); + } + + if (action != null) + action.traverse(visitor, scope); + } + visitor.endVisit(this, blockScope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/IfStatement.java b/src/java/org/eclipse/jdt/internal/compiler/ast/IfStatement.java new file mode 100644 index 0000000..a262104 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/IfStatement.java @@ -0,0 +1,244 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class IfStatement extends Statement { + + //this class represents the case of only one statement in + //either else and/or then branches. + + public Expression condition; + public Statement thenStatement; + public Statement elseStatement; + + boolean thenExit; + + // for local variables table attributes + int thenInitStateIndex = -1; + int elseInitStateIndex = -1; + int mergedInitStateIndex = -1; + + public IfStatement(Expression condition, Statement thenStatement, int sourceStart, int sourceEnd) { + + this.condition = condition; + this.thenStatement = thenStatement; + // remember useful empty statement + if (thenStatement instanceof EmptyStatement) thenStatement.bits |= IsUsefulEmptyStatementMASK; + this.sourceStart = sourceStart; + this.sourceEnd = sourceEnd; + } + + public IfStatement(Expression condition, Statement thenStatement, Statement elseStatement, int sourceStart, int sourceEnd) { + + this.condition = condition; + this.thenStatement = thenStatement; + // remember useful empty statement + if (thenStatement instanceof EmptyStatement) thenStatement.bits |= IsUsefulEmptyStatementMASK; + this.elseStatement = elseStatement; + if (elseStatement instanceof IfStatement) elseStatement.bits |= IsElseIfStatement; + this.sourceStart = sourceStart; + this.sourceEnd = sourceEnd; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + // process the condition + flowInfo = condition.analyseCode(currentScope, flowContext, flowInfo); + + Constant cst = this.condition.optimizedBooleanConstant(); + boolean isConditionOptimizedTrue = cst != NotAConstant && cst.booleanValue() == true; + boolean isConditionOptimizedFalse = cst != NotAConstant && cst.booleanValue() == false; + + // process the THEN part + FlowInfo thenFlowInfo = flowInfo.initsWhenTrue().copy(); + if (isConditionOptimizedFalse) { + thenFlowInfo.setReachMode(FlowInfo.UNREACHABLE); + } + if (this.thenStatement != null) { + // Save info for code gen + thenInitStateIndex = + currentScope.methodScope().recordInitializationStates(thenFlowInfo); + if (!thenStatement.complainIfUnreachable(thenFlowInfo, currentScope, false)) { + thenFlowInfo = + thenStatement.analyseCode(currentScope, flowContext, thenFlowInfo); + } + } + // code gen: optimizing the jump around the ELSE part + this.thenExit = !thenFlowInfo.isReachable(); + + // process the ELSE part + FlowInfo elseFlowInfo = flowInfo.initsWhenFalse().copy(); + if (isConditionOptimizedTrue) { + elseFlowInfo.setReachMode(FlowInfo.UNREACHABLE); + } + if (this.elseStatement != null) { + // signal else clause unnecessarily nested, tolerate else-if code pattern + if (thenFlowInfo == FlowInfo.DEAD_END + && (this.bits & IsElseIfStatement) == 0 // else of an else-if + && !(this.elseStatement instanceof IfStatement)) { + currentScope.problemReporter().unnecessaryElse(this.elseStatement); + } + // Save info for code gen + elseInitStateIndex = + currentScope.methodScope().recordInitializationStates(elseFlowInfo); + if (!elseStatement.complainIfUnreachable(elseFlowInfo, currentScope, false)) { + elseFlowInfo = + elseStatement.analyseCode(currentScope, flowContext, elseFlowInfo); + } + } + + // merge THEN & ELSE initializations + FlowInfo mergedInfo = FlowInfo.mergedOptimizedBranches( + thenFlowInfo, + isConditionOptimizedTrue, + elseFlowInfo, + isConditionOptimizedFalse, + true /*if(true){ return; } fake-reachable(); */); + mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo); + return mergedInfo; + } + + /** + * If code generation + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + + if ((this.bits & IsReachableMASK) == 0) { + return; + } + int pc = codeStream.position; + Label endifLabel = new Label(codeStream); + + // optimizing the then/else part code gen + Constant cst; + boolean hasThenPart = + !(((cst = this.condition.optimizedBooleanConstant()) != NotAConstant + && cst.booleanValue() == false) + || this.thenStatement == null + || this.thenStatement.isEmptyBlock()); + boolean hasElsePart = + !((cst != NotAConstant && cst.booleanValue() == true) + || this.elseStatement == null + || this.elseStatement.isEmptyBlock()); + + if (hasThenPart) { + Label falseLabel; + // generate boolean condition + this.condition.generateOptimizedBoolean( + currentScope, + codeStream, + null, + (falseLabel = new Label(codeStream)), + true); + // May loose some local variable initializations : affecting the local variable attributes + if (thenInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + thenInitStateIndex); + codeStream.addDefinitelyAssignedVariables(currentScope, thenInitStateIndex); + } + // generate then statement + this.thenStatement.generateCode(currentScope, codeStream); + // jump around the else statement + if (hasElsePart && !thenExit) { + this.thenStatement.branchChainTo(endifLabel); + int position = codeStream.position; + codeStream.goto_(endifLabel); + codeStream.updateLastRecordedEndPC(position); + //goto is tagged as part of the thenAction block + } + falseLabel.place(); + } else { + if (hasElsePart) { + // generate boolean condition + this.condition.generateOptimizedBoolean( + currentScope, + codeStream, + endifLabel, + null, + true); + } else { + // generate condition side-effects + this.condition.generateCode(currentScope, codeStream, false); + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + } + // generate else statement + if (hasElsePart) { + // May loose some local variable initializations : affecting the local variable attributes + if (elseInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + elseInitStateIndex); + codeStream.addDefinitelyAssignedVariables(currentScope, elseInitStateIndex); + } + this.elseStatement.generateCode(currentScope, codeStream); + } + endifLabel.place(); + // May loose some local variable initializations : affecting the local variable attributes + if (mergedInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + mergedInitStateIndex); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public StringBuffer printStatement(int indent, StringBuffer output) { + + printIndent(indent, output).append("if ("); //$NON-NLS-1$ + condition.printExpression(0, output).append(")\n"); //$NON-NLS-1$ + thenStatement.printStatement(indent + 2, output); + if (elseStatement != null) { + output.append('\n'); + printIndent(indent, output); + output.append("else\n"); //$NON-NLS-1$ + elseStatement.printStatement(indent + 2, output); + } + return output; + } + + public void resolve(BlockScope scope) { + + TypeBinding type = condition.resolveTypeExpecting(scope, BooleanBinding); + condition.implicitWidening(type, type); + if (thenStatement != null) + thenStatement.resolve(scope); + if (elseStatement != null) + elseStatement.resolve(scope); + } + + public void traverse( + ASTVisitor visitor, + BlockScope blockScope) { + + if (visitor.visit(this, blockScope)) { + condition.traverse(visitor, blockScope); + if (thenStatement != null) + thenStatement.traverse(visitor, blockScope); + if (elseStatement != null) + elseStatement.traverse(visitor, blockScope); + } + visitor.endVisit(this, blockScope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/ImplicitDocTypeReference.java b/src/java/org/eclipse/jdt/internal/compiler/ast/ImplicitDocTypeReference.java new file mode 100644 index 0000000..9dda67e --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/ImplicitDocTypeReference.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.lookup.ClassScope; +import org.eclipse.jdt.internal.compiler.lookup.Scope; +import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; + +public class ImplicitDocTypeReference extends TypeReference { + + public char[] token; + + public ImplicitDocTypeReference(char[] name, int pos) { + super(); + this.token = name; + this.sourceStart = pos; + this.sourceEnd = pos; + } + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.ast.TypeReference#copyDims(int) + */ + public TypeReference copyDims(int dim) { + return null; + } + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.ast.TypeReference#getTypeBinding(org.eclipse.jdt.internal.compiler.lookup.Scope) + */ + public TypeBinding getTypeBinding(Scope scope) { + this.constant = NotAConstant; + return this.resolvedType = scope.enclosingSourceType(); + } + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.ast.TypeReference#getTypeName() + */ + public char[][] getTypeName() { + if (this.token != null) { + char[][] tokens = { this.token }; + return tokens; + } + return null; + } + public boolean isThis() { + return true; + } + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.ast.TypeReference#traverse(org.eclipse.jdt.internal.compiler.ASTVisitor, org.eclipse.jdt.internal.compiler.lookup.ClassScope) + */ + public void traverse(ASTVisitor visitor, ClassScope classScope) { + // Do nothing + } + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.ast.Expression#printExpression(int, java.lang.StringBuffer) + */ + public StringBuffer printExpression(int indent, StringBuffer output) { + return new StringBuffer(); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/ImportReference.java b/src/java/org/eclipse/jdt/internal/compiler/ast/ImportReference.java new file mode 100644 index 0000000..4623b2d --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/ImportReference.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class ImportReference extends ASTNode { + + public char[][] tokens; + public long[] sourcePositions; //each entry is using the code : (start<<32) + end + public boolean onDemand = true; //most of the time + public int declarationEnd; // doesn't include an potential trailing comment + public int declarationSourceStart; + public int declarationSourceEnd; + public boolean used; + public int modifiers; // 1.5 addition for static imports + + public ImportReference( + char[][] tokens, + long[] sourcePositions, + boolean onDemand, + int modifiers) { + + this.tokens = tokens; + this.sourcePositions = sourcePositions; + this.onDemand = onDemand; + this.sourceEnd = (int) (sourcePositions[sourcePositions.length-1] & 0x00000000FFFFFFFF); + this.sourceStart = (int) (sourcePositions[0] >>> 32); + this.modifiers = modifiers; + } + + /** + * @return char[][] + */ + public char[][] getImportName() { + + return tokens; + } + + public StringBuffer print(int indent, StringBuffer output) { + + return print(indent, output, true); + } + + public StringBuffer print(int tab, StringBuffer output, boolean withOnDemand) { + + /* when withOnDemand is false, only the name is printed */ + for (int i = 0; i < tokens.length; i++) { + if (i > 0) output.append('.'); + output.append(tokens[i]); + } + if (withOnDemand && onDemand) { + output.append(".*"); //$NON-NLS-1$ + } + return output; + } + + public void traverse(ASTVisitor visitor, CompilationUnitScope scope) { + + visitor.visit(this, scope); + visitor.endVisit(this, scope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/Initializer.java b/src/java/org/eclipse/jdt/internal/compiler/ast/Initializer.java new file mode 100644 index 0000000..ff53718 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/Initializer.java @@ -0,0 +1,120 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; +import org.eclipse.jdt.internal.compiler.parser.*; + +public class Initializer extends FieldDeclaration { + + public Block block; + public int lastVisibleFieldID; + public int bodyStart; + public int bodyEnd; + + public boolean errorInSignature = false; + + public Initializer(Block block, int modifiers) { + this.block = block; + this.modifiers = modifiers; + + declarationSourceStart = sourceStart = block.sourceStart; + } + + public FlowInfo analyseCode( + MethodScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + return block.analyseCode(currentScope, flowContext, flowInfo); + } + + /** + * Code generation for a non-static initializer: + * standard block code gen + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + + if ((bits & IsReachableMASK) == 0) { + return; + } + int pc = codeStream.position; + block.generateCode(currentScope, codeStream); + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public boolean isField() { + + return false; + } + + public boolean isStatic() { + + return (modifiers & AccStatic) != 0; + } + + public void parseStatements( + Parser parser, + TypeDeclaration typeDeclaration, + CompilationUnitDeclaration unit) { + + //fill up the method body with statement + parser.parse(this, typeDeclaration, unit); + } + + public StringBuffer printStatement(int indent, StringBuffer output) { + + if (modifiers != 0) { + printIndent(indent, output); + printModifiers(modifiers, output).append("{\n"); //$NON-NLS-1$ + block.printBody(indent, output); + printIndent(indent, output).append('}'); + return output; + } else { + return block.printStatement(indent, output); + } + } + + public void resolve(MethodScope scope) { + + FieldBinding previousField = scope.initializedField; + int previousFieldID = scope.lastVisibleFieldID; + try { + scope.initializedField = null; + scope.lastVisibleFieldID = lastVisibleFieldID; + if (isStatic()) { + ReferenceBinding declaringType = scope.enclosingSourceType(); + if (declaringType.isNestedType() && !declaringType.isStatic()) + scope.problemReporter().innerTypesCannotDeclareStaticInitializers( + declaringType, + this); + } + block.resolve(scope); + } finally { + scope.initializedField = previousField; + scope.lastVisibleFieldID = previousFieldID; + } + } + + public void traverse(ASTVisitor visitor, MethodScope scope) { + + if (visitor.visit(this, scope)) { + block.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java b/src/java/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java new file mode 100644 index 0000000..feacdaf --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java @@ -0,0 +1,223 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class InstanceOfExpression extends OperatorExpression { + + public Expression expression; + public TypeReference type; + + public InstanceOfExpression( + Expression expression, + TypeReference type, + int operator) { + + this.expression = expression; + this.type = type; + this.bits |= operator << OperatorSHIFT; + this.sourceStart = expression.sourceStart; + this.sourceEnd = type.sourceEnd; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + return expression + .analyseCode(currentScope, flowContext, flowInfo) + .unconditionalInits(); + } + /** + * Returns false if the instanceof unnecessary + */ + public final boolean checkCastTypesCompatibility( + BlockScope scope, + TypeBinding castType, + TypeBinding expressionType) { + + //A more complete version of this method is provided on + //CastExpression (it deals with constant and need runtime checkcast) + + if (castType == expressionType) return false; + + //by grammatical construction, the base type check is not necessary + + if (castType == null || expressionType == null) return true; + + //-----------cast to something which is NOT a base type-------------------------- + if (expressionType == NullBinding) { + // if (castType.isArrayType()){ // 26903 - need checkcast when casting null to array type + // needRuntimeCheckcast = true; + // } + return false; //null is compatible with every thing + } + if (expressionType.isBaseType()) { + scope.problemReporter().notCompatibleTypesError(this, expressionType, castType); + return true; + } + + if (expressionType.isArrayType()) { + if (castType == expressionType) return false; // identity conversion + + if (castType.isArrayType()) { + //------- (castType.isArray) expressionType.isArray ----------- + TypeBinding exprElementType = ((ArrayBinding) expressionType).elementsType(scope); + if (exprElementType.isBaseType()) { + // <---stop the recursion------- + if (((ArrayBinding) castType).elementsType(scope) != exprElementType) + scope.problemReporter().notCompatibleTypesError(this, expressionType, castType); + return true; + } + // recursively on the elements... + return checkCastTypesCompatibility( + scope, + ((ArrayBinding) castType).elementsType(scope), + exprElementType); + } else if ( + castType.isClass()) { + //------(castType.isClass) expressionType.isArray --------------- + if (castType.id == T_Object) { + return false; + } + } else { //------- (castType.isInterface) expressionType.isArray ----------- + if (castType.id == T_JavaLangCloneable || castType.id == T_JavaIoSerializable) { + return true; + } + } + scope.problemReporter().notCompatibleTypesError(this, expressionType, castType); + return true; + } + + if (expressionType.isClass()) { + if (castType.isArrayType()) { + // ---- (castType.isArray) expressionType.isClass ------- + if (expressionType.id == T_Object) { // potential runtime error + return true; + } + } else if (castType.isClass()) { // ----- (castType.isClass) expressionType.isClass ------ + if (expressionType.isCompatibleWith(castType)){ // no runtime error + return false; + } + if (castType.isCompatibleWith(expressionType)) { + // potential runtime error + return true; + } + } else { // ----- (castType.isInterface) expressionType.isClass ------- + if (expressionType.isCompatibleWith(castType)) + return false; + if (!((ReferenceBinding) expressionType).isFinal()) { + // a subclass may implement the interface ==> no check at compile time + return true; + } + // no subclass for expressionType, thus compile-time check is valid + } + scope.problemReporter().notCompatibleTypesError(this, expressionType, castType); + return true; + } + + // if (expressionType.isInterface()) { cannot be anything else + if (castType.isArrayType()) { + // ----- (castType.isArray) expressionType.isInterface ------ + if (!(expressionType.id == T_JavaLangCloneable + || expressionType.id == T_JavaIoSerializable)) {// potential runtime error + scope.problemReporter().notCompatibleTypesError(this, expressionType, castType); + } + return true; + } else if (castType.isClass()) { // ----- (castType.isClass) expressionType.isInterface -------- + if (castType.id == T_Object) { // no runtime error + return false; + } + if (((ReferenceBinding) castType).isFinal()) { + // no subclass for castType, thus compile-time check is valid + if (!castType.isCompatibleWith(expressionType)) { + // potential runtime error + scope.problemReporter().notCompatibleTypesError(this, expressionType, castType); + return true; + } + } + } else { // ----- (castType.isInterface) expressionType.isInterface ------- + if (expressionType.isCompatibleWith(castType)) { + return false; + } + if (!castType.isCompatibleWith(expressionType)) { + MethodBinding[] castTypeMethods = ((ReferenceBinding) castType).methods(); + MethodBinding[] expressionTypeMethods = + ((ReferenceBinding) expressionType).methods(); + int exprMethodsLength = expressionTypeMethods.length; + for (int i = 0, castMethodsLength = castTypeMethods.length; i < castMethodsLength; i++) + for (int j = 0; j < exprMethodsLength; j++) { + if ((castTypeMethods[i].returnType != expressionTypeMethods[j].returnType) + && CharOperation.equals(castTypeMethods[i].selector, expressionTypeMethods[j].selector) + && castTypeMethods[i].areParametersEqual(expressionTypeMethods[j])) { + scope.problemReporter().notCompatibleTypesError(this, expressionType, castType); + } + } + } + } + return true; + } + /** + * Code generation for instanceOfExpression + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ + public void generateCode( + BlockScope currentScope, + CodeStream codeStream, + boolean valueRequired) { + + int pc = codeStream.position; + expression.generateCode(currentScope, codeStream, true); + codeStream.instance_of(type.resolvedType); + if (!valueRequired) + codeStream.pop(); + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public StringBuffer printExpressionNoParenthesis(int indent, StringBuffer output) { + + expression.printExpression(indent, output).append(" instanceof "); //$NON-NLS-1$ + return type.print(0, output); + } + + public TypeBinding resolveType(BlockScope scope) { + + constant = NotAConstant; + TypeBinding expressionType = expression.resolveType(scope); + TypeBinding checkType = type.resolveType(scope); + if (expressionType == null || checkType == null) + return null; + + boolean necessary = checkCastTypesCompatibility(scope, checkType, expressionType); + if (!necessary) { + scope.problemReporter().unnecessaryInstanceof(this, checkType); + } + return this.resolvedType = BooleanBinding; + } + + public void traverse(ASTVisitor visitor, BlockScope scope) { + + if (visitor.visit(this, scope)) { + expression.traverse(visitor, scope); + type.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/IntLiteral.java b/src/java/org/eclipse/jdt/internal/compiler/ast/IntLiteral.java new file mode 100644 index 0000000..46a2172 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/IntLiteral.java @@ -0,0 +1,150 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class IntLiteral extends NumberLiteral { + public int value; + + public static final IntLiteral + One = new IntLiteral(new char[]{'1'},0,0,1);//used for ++ and -- + + static final Constant FORMAT_ERROR = new DoubleConstant(1.0/0.0); // NaN; +public IntLiteral(char[] token, int s, int e) { + super(token, s,e); +} +public IntLiteral(char[] token, int s,int e, int value) { + this(token, s,e); + this.value = value; +} +public IntLiteral(int intValue) { + //special optimized constructor : the cst is the argument + + //value that should not be used + // tokens = null ; + // sourceStart = 0; + // sourceEnd = 0; + super(null,0,0); + constant = Constant.fromValue(intValue); + value = intValue; + +} +public void computeConstant() { + //a special constant is use for the potential Integer.MAX_VALUE+1 + //which is legal if used with a - as prefix....cool.... + //notice that Integer.MIN_VALUE == -2147483648 + + long MAX = Integer.MAX_VALUE; + if (this == One) { constant = Constant.One; return ;} + + int length = source.length; + long computedValue = 0L; + if (source[0] == '0') + { MAX = 0xFFFFFFFFL ; //a long in order to be positive ! + if (length == 1) { constant = Constant.fromValue(0); return ;} + final int shift,radix; + int j ; + if ( (source[1] == 'x') | (source[1] == 'X') ) + { shift = 4 ; j = 2; radix = 16;} + else + { shift = 3 ; j = 1; radix = 8;} + while (source[j]=='0') + { j++; //jump over redondant zero + if (j == length) + { //watch for 000000000000000000 + constant = Constant.fromValue(value = (int)computedValue); + return ;}} + + while (j MAX) return /*constant stays null*/ ;}} + else + { //-----------regular case : radix = 10----------- + for (int i = 0 ; i < length;i++) + { int digitValue ; + if ((digitValue = Character.digit(source[i],10)) < 0 ) + { constant = FORMAT_ERROR; return ;} + computedValue = 10*computedValue + digitValue; + if (computedValue > MAX) return /*constant stays null*/ ; }} + + constant = Constant.fromValue(value = (int)computedValue); + +} +/** + * Code generation for int literal + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ +public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { + int pc = codeStream.position; + if (valueRequired) + if ((implicitConversion >> 4) == T_int) + codeStream.generateInlinedValue(value); + else + codeStream.generateConstant(constant, implicitConversion); + codeStream.recordPositionsFrom(pc, this.sourceStart); +} +public TypeBinding literalType(BlockScope scope) { + return IntBinding; +} +public final boolean mayRepresentMIN_VALUE(){ + //a special autorized int literral is 2147483648 + //which is ONE over the limit. This special case + //only is used in combinaison with - to denote + //the minimal value of int -2147483648 + + return ((source.length == 10) && + (source[0] == '2') && + (source[1] == '1') && + (source[2] == '4') && + (source[3] == '7') && + (source[4] == '4') && + (source[5] == '8') && + (source[6] == '3') && + (source[7] == '6') && + (source[8] == '4') && + (source[9] == '8'));} +public TypeBinding resolveType(BlockScope scope) { + // the format may be incorrect while the scanner could detect + // such an error only on painfull tests...easier and faster here + + TypeBinding tb = super.resolveType(scope); + if (constant == FORMAT_ERROR) { + constant = NotAConstant; + scope.problemReporter().constantOutOfFormat(this); + this.resolvedType = null; + return null; + } + return tb; +} +public StringBuffer printExpression(int indent, StringBuffer output){ + + if (source == null) { + /* special optimized IntLiteral that are created by the compiler */ + return output.append(String.valueOf(value)); + } + return super.printExpression(indent, output); +} + +public void traverse(ASTVisitor visitor, BlockScope scope) { + visitor.visit(this, scope); + visitor.endVisit(this, scope); +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/IntLiteralMinValue.java b/src/java/org/eclipse/jdt/internal/compiler/ast/IntLiteralMinValue.java new file mode 100644 index 0000000..9700282 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/IntLiteralMinValue.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.impl.*; + +public class IntLiteralMinValue extends IntLiteral { + + final static char[] CharValue = new char[]{'-','2','1','4','7','4','8','3','6','4','8'}; + final static Constant MIN_VALUE = Constant.fromValue(Integer.MIN_VALUE) ; + +public IntLiteralMinValue() { + super(CharValue,0,0,Integer.MIN_VALUE); + constant = MIN_VALUE; +} +public void computeConstant(){ + + /*precomputed at creation time*/ } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/Javadoc.java b/src/java/org/eclipse/jdt/internal/compiler/ast/Javadoc.java new file mode 100644 index 0000000..f683964 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/Javadoc.java @@ -0,0 +1,469 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.lookup.*; + +/** + * Node representing a structured Javadoc comment + */ +public class Javadoc extends ASTNode { + + public JavadocSingleNameReference[] parameters; // @param + public TypeReference[] thrownExceptions; // @throws, @exception + public JavadocReturnStatement returnStatement; // @return + public Expression[] references; // @see + public boolean inherited = false; + // bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=51600 + // Store param references for tag with invalid syntax + public JavadocSingleNameReference[] invalidParameters; // @param + + public Javadoc(int sourceStart, int sourceEnd) { + this.sourceStart = sourceStart; + this.sourceEnd = sourceEnd; + } + + /* + * @see org.eclipse.jdt.internal.compiler.ast.ASTNode#print(int, java.lang.StringBuffer) + */ + public StringBuffer print(int indent, StringBuffer output) { + printIndent(indent, output).append("/**\n"); //$NON-NLS-1$ + if (this.parameters != null) { + for (int i = 0, length = this.parameters.length; i < length; i++) { + printIndent(indent + 1, output).append(" * @param "); //$NON-NLS-1$ + this.parameters[i].print(indent, output).append('\n'); + } + } + if (this.returnStatement != null) { + printIndent(indent + 1, output).append(" * @return\n"); //$NON-NLS-1$ + } + if (this.thrownExceptions != null) { + for (int i = 0, length = this.thrownExceptions.length; i < length; i++) { + printIndent(indent + 1, output).append(" * @throws "); //$NON-NLS-1$ + this.thrownExceptions[i].print(indent, output).append('\n'); + } + } + if (this.references != null) { + for (int i = 0, length = this.references.length; i < length; i++) { + printIndent(indent + 1, output).append(" * @see"); //$NON-NLS-1$ + this.references[i].print(indent, output).append('\n'); + } + } + printIndent(indent, output).append(" */\n"); //$NON-NLS-1$ + return output; + } + + /* + * Resolve type javadoc while a class scope + */ + public void resolve(ClassScope classScope) { + + + // @param tags + int paramTagsSize = this.parameters == null ? 0 : this.parameters.length; + for (int i = 0; i < paramTagsSize; i++) { + JavadocSingleNameReference param = this.parameters[i]; + classScope.problemReporter().javadocUnexpectedTag(param.tagSourceStart, param.tagSourceEnd); + } + + // @return tags + if (this.returnStatement != null) { + classScope.problemReporter().javadocUnexpectedTag(this.returnStatement.sourceStart, this.returnStatement.sourceEnd); + } + + // @throws/@exception tags + int throwsTagsLength = this.thrownExceptions == null ? 0 : this.thrownExceptions.length; + for (int i = 0; i < throwsTagsLength; i++) { + TypeReference typeRef = this.thrownExceptions[i]; + int start, end; + if (typeRef instanceof JavadocSingleTypeReference) { + JavadocSingleTypeReference singleRef = (JavadocSingleTypeReference) typeRef; + start = singleRef.tagSourceStart; + end = singleRef.tagSourceEnd; + } else if (typeRef instanceof JavadocQualifiedTypeReference) { + JavadocQualifiedTypeReference qualifiedRef = (JavadocQualifiedTypeReference) typeRef; + start = qualifiedRef.tagSourceStart; + end = qualifiedRef.tagSourceEnd; + } else { + start = typeRef.sourceStart; + end = typeRef.sourceEnd; + } + classScope.problemReporter().javadocUnexpectedTag(start, end); + } + + // @see tags + int seeTagsLength = this.references == null ? 0 : this.references.length; + for (int i = 0; i < seeTagsLength; i++) { + + // Resolve reference + this.references[i].resolveType(classScope); + + // Some unbound field reference might be changed to message send + // see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=51911 + if (this.references[i] instanceof JavadocFieldReference) { + JavadocFieldReference fieldRef = (JavadocFieldReference) this.references[i]; + if (fieldRef.receiverType != null && fieldRef.binding == null) { // binding was reset in case of valid method reference + // TODO (frederic) post 3.0 - avoid new instanciation of Compiler AST node + JavadocMessageSend msgSend = new JavadocMessageSend(fieldRef.token, fieldRef.nameSourcePosition); + msgSend.receiver = fieldRef.receiver; + msgSend.receiverType = fieldRef.receiverType; + msgSend.qualifyingType = fieldRef.receiverType; + msgSend.superAccess = classScope.enclosingSourceType().isCompatibleWith(msgSend.receiverType); + msgSend.binding = classScope.findMethod((ReferenceBinding)msgSend.receiverType, msgSend.selector, new TypeBinding[0], msgSend); + this.references[i] = msgSend; + } + } + } + } + + /* + * Resolve method javadoc while a method scope + */ + public void resolve(MethodScope methScope) { + + // get method declaration + AbstractMethodDeclaration methDecl = methScope.referenceMethod(); + boolean overriding = methDecl == null ? false : (methDecl.binding.modifiers & (AccImplementing+AccOverriding)) != 0; + + // @see tags + int seeTagsLength = this.references == null ? 0 : this.references.length; + boolean superRef = false; + for (int i = 0; i < seeTagsLength; i++) { + + // Resolve reference + this.references[i].resolveType(methScope); + + // Some unbound field reference might be changed to message send + // see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=51911 + if (this.references[i] instanceof JavadocFieldReference) { + JavadocFieldReference fieldRef = (JavadocFieldReference) this.references[i]; + if (fieldRef.receiverType != null && fieldRef.binding == null) { // binding was reset in case of valid method reference + // TODO (frederic) post 3.0 - avoid new instanciation of Compiler AST node + JavadocMessageSend msgSend = new JavadocMessageSend(fieldRef.token, fieldRef.nameSourcePosition); + msgSend.receiver = fieldRef.receiver; + msgSend.receiverType = fieldRef.receiverType; + msgSend.qualifyingType = fieldRef.receiverType; + msgSend.superAccess = methScope.enclosingSourceType().isCompatibleWith(msgSend.receiverType); + msgSend.binding = methScope.findMethod((ReferenceBinding)msgSend.receiverType, msgSend.selector, new TypeBinding[0], msgSend); + this.references[i] = msgSend; + } + } + + // see whether we can have a super reference + try { + if (methDecl != null && (methDecl.isConstructor() || overriding) && !superRef) { + if (this.references[i] instanceof JavadocMessageSend) { + JavadocMessageSend messageSend = (JavadocMessageSend) this.references[i]; + // if binding is valid then look if we have a reference to an overriden method/constructor + if (messageSend.binding != null && messageSend.binding.isValidBinding()) { + if (methDecl.binding.declaringClass.isCompatibleWith(messageSend.receiverType) && + CharOperation.equals(messageSend.selector, methDecl.selector) && + (messageSend.binding.returnType == methDecl.binding.returnType)) { + if (messageSend.arguments == null && methDecl.arguments == null) { + superRef = true; + } + else if (messageSend.arguments != null && methDecl.arguments != null) { + superRef = methDecl.binding.areParametersEqual(messageSend.binding); + } + } + } + } + else if (this.references[i] instanceof JavadocAllocationExpression) { + JavadocAllocationExpression allocationExpr = (JavadocAllocationExpression) this.references[i]; + // if binding is valid then look if we have a reference to an overriden method/constructor + if (allocationExpr.binding != null && allocationExpr.binding.isValidBinding()) { + if (methDecl.binding.declaringClass.isCompatibleWith(allocationExpr.resolvedType)) { + if (allocationExpr.arguments == null && methDecl.arguments == null) { + superRef = true; + } + else if (allocationExpr.arguments != null && methDecl.arguments != null) { + superRef = methDecl.binding.areParametersEqual(allocationExpr.binding); + } + } + } + } + } + } + catch (Exception e) { + // Something wrong happen, forget super ref... + } + } + + // Store if a reference exists to an overriden method/constructor or the method is in a local type, + boolean reportMissing = methDecl == null || !((overriding && this.inherited) || superRef || (methDecl.binding.declaringClass != null && methDecl.binding.declaringClass.isLocalType())); + + // @param tags + resolveParamTags(methScope, reportMissing); + + // @return tags + if (this.returnStatement == null) { + if (reportMissing && methDecl != null) { + if (!methDecl.isConstructor() && !methDecl.isClinit()) { + MethodDeclaration meth = (MethodDeclaration) methDecl; + if (meth.binding.returnType != VoidBinding) { + // method with return should have @return tag + methScope.problemReporter().javadocMissingReturnTag(meth.returnType.sourceStart, meth.returnType.sourceEnd, methDecl.binding.modifiers); + } + } + } + } else { + this.returnStatement.resolve(methScope); + } + + // @throws/@exception tags + resolveThrowsTags(methScope, reportMissing); + + // Resolve param tags with invalid syntax + int length = this.invalidParameters == null ? 0 : this.invalidParameters.length; + for (int i = 0; i < length; i++) { + this.invalidParameters[i].resolve(methScope, false); + } + } + + /* + * Resolve @param tags while method scope + */ + private void resolveParamTags(MethodScope methScope, boolean reportMissing) { + AbstractMethodDeclaration md = methScope.referenceMethod(); + int paramTagsSize = this.parameters == null ? 0 : this.parameters.length; + + // If no referenced method (field initializer for example) then report a problem for each param tag + if (md == null) { + for (int i = 0; i < paramTagsSize; i++) { + JavadocSingleNameReference param = this.parameters[i]; + methScope.problemReporter().javadocUnexpectedTag(param.tagSourceStart, param.tagSourceEnd); + } + return; + } + + // If no param tags then report a problem for each method argument + int argumentsSize = md.arguments == null ? 0 : md.arguments.length; + if (paramTagsSize == 0) { + if (reportMissing) { + for (int i = 0; i < argumentsSize; i++) { + Argument arg = md.arguments[i]; + methScope.problemReporter().javadocMissingParamTag(arg, md.binding.modifiers); + } + } + } else { + LocalVariableBinding[] bindings = new LocalVariableBinding[paramTagsSize]; + int maxBindings = 0; + + // Scan all @param tags + for (int i = 0; i < paramTagsSize; i++) { + JavadocSingleNameReference param = this.parameters[i]; + param.resolve(methScope); + if (param.binding != null && param.binding.isValidBinding()) { + // Verify duplicated tags + boolean found = false; + for (int j = 0; j < maxBindings && !found; j++) { + if (bindings[j] == param.binding) { + methScope.problemReporter().javadocDuplicatedParamTag(param, md.binding.modifiers); + found = true; + } + } + if (!found) { + bindings[maxBindings++] = (LocalVariableBinding) param.binding; + } + } + } + + // Look for undocumented arguments + if (reportMissing) { + for (int i = 0; i < argumentsSize; i++) { + Argument arg = md.arguments[i]; + boolean found = false; + for (int j = 0; j < maxBindings && !found; j++) { + LocalVariableBinding binding = bindings[j]; + if (arg.binding == binding) { + found = true; + } + } + if (!found) { + methScope.problemReporter().javadocMissingParamTag(arg, md.binding.modifiers); + } + } + } + } + } + + /* + * Resolve @throws/@exception tags while method scope + */ + private void resolveThrowsTags(MethodScope methScope, boolean reportMissing) { + AbstractMethodDeclaration md = methScope.referenceMethod(); + int throwsTagsLength = this.thrownExceptions == null ? 0 : this.thrownExceptions.length; + + // If no referenced method (field initializer for example) then report a problem for each throws tag + if (md == null) { + for (int i = 0; i < throwsTagsLength; i++) { + TypeReference typeRef = this.thrownExceptions[i]; + int start = typeRef.sourceStart; + int end = typeRef.sourceEnd; + if (typeRef instanceof JavadocQualifiedTypeReference) { + start = ((JavadocQualifiedTypeReference) typeRef).tagSourceStart; + end = ((JavadocQualifiedTypeReference) typeRef).tagSourceEnd; + } else if (typeRef instanceof JavadocSingleTypeReference) { + start = ((JavadocSingleTypeReference) typeRef).tagSourceStart; + end = ((JavadocSingleTypeReference) typeRef).tagSourceEnd; + } + methScope.problemReporter().javadocUnexpectedTag(start, end); + } + return; + } + + // If no throws tags then report a problem for each method thrown exception + int boundExceptionLength = (md.binding == null || md.binding.thrownExceptions == null) ? 0 : md.binding.thrownExceptions.length; + int thrownExceptionLength = md.thrownExceptions == null ? 0 : md.thrownExceptions.length; + if (throwsTagsLength == 0) { + if (reportMissing) { + for (int i = 0; i < boundExceptionLength; i++) { + ReferenceBinding exceptionBinding = md.binding.thrownExceptions[i]; + if (exceptionBinding != null && exceptionBinding.isValidBinding()) { // flag only valid class name + int j=i; + while (j>> 32); + this.sourceEnd = (int) pos; + this.bits |= InsideJavadoc; + } + + /* + * Resolves type on a Block or Class scope. + */ + private TypeBinding internalResolveType(Scope scope) { + + // Propagate the type checking to the arguments, and check if the constructor is defined. + this.constant = NotAConstant; + if (this.type == null) { + this.resolvedType = scope.enclosingSourceType(); + } else if (scope.kind == Scope.CLASS_SCOPE) { + this.resolvedType = this.type.resolveType((ClassScope)scope); + } else { + this.resolvedType = this.type.resolveType((BlockScope)scope); + } + + // buffering the arguments' types + TypeBinding[] argumentTypes = NoParameters; + if (this.arguments != null) { + boolean argHasError = false; + int length = this.arguments.length; + argumentTypes = new TypeBinding[length]; + for (int i = 0; i < length; i++) { + Expression argument = this.arguments[i]; + if (scope.kind == Scope.CLASS_SCOPE) { + argumentTypes[i] = argument.resolveType((ClassScope)scope); + } else { + argumentTypes[i] = argument.resolveType((BlockScope)scope); + } + if (argumentTypes[i] == null) { + argHasError = true; + } + } + if (argHasError) { + return null; + } + } + + // check resolved type + if (this.resolvedType == null) { + return null; + } + this.superAccess = scope.enclosingSourceType().isCompatibleWith(this.resolvedType); + + ReferenceBinding allocationType = (ReferenceBinding) this.resolvedType; + this.binding = scope.getConstructor(allocationType, argumentTypes, this); + if (!this.binding.isValidBinding()) { + MethodBinding methodBinding = scope.getMethod(this.resolvedType, this.resolvedType.sourceName(), argumentTypes, this); + if (methodBinding.isValidBinding()) { + this.binding = methodBinding; + } else { + if (this.binding.declaringClass == null) { + this.binding.declaringClass = allocationType; + } + scope.problemReporter().javadocInvalidConstructor(this, this.binding, scope.getDeclarationModifiers()); + } + return this.resolvedType; + } + if (isMethodUseDeprecated(this.binding, scope)) { + scope.problemReporter().javadocDeprecatedMethod(this.binding, this, scope.getDeclarationModifiers()); + } + + return allocationType; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#isSuperAccess() + */ + public boolean isSuperAccess() { + return this.superAccess; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.ast.Expression#resolveType(org.eclipse.jdt.internal.compiler.lookup.BlockScope) + */ + public TypeBinding resolveType(BlockScope scope) { + return internalResolveType(scope); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.ast.Expression#resolveType(org.eclipse.jdt.internal.compiler.lookup.BlockScope) + */ + public TypeBinding resolveType(ClassScope scope) { + return internalResolveType(scope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/JavadocArgumentExpression.java b/src/java/org/eclipse/jdt/internal/compiler/ast/JavadocArgumentExpression.java new file mode 100644 index 0000000..57be26e --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/JavadocArgumentExpression.java @@ -0,0 +1,102 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.env.IConstants; +import org.eclipse.jdt.internal.compiler.lookup.*; +import org.eclipse.jdt.internal.compiler.lookup.BlockScope; +import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; + + +public class JavadocArgumentExpression extends Expression { + public char[] token; + public Argument argument; + + public JavadocArgumentExpression(char[] name, int startPos, int endPos, TypeReference typeRef) { + this.token = name; + this.sourceStart = startPos; + this.sourceEnd = endPos; + long pos = (((long) startPos) << 32) + endPos; + this.argument = new Argument(name, pos, typeRef, IConstants.AccDefault); + this.bits |= InsideJavadoc; + } + + /* + * Resolves type on a Block or Class scope. + */ + private TypeBinding internalResolveType(Scope scope) { + this.constant = NotAConstant; + if (this.resolvedType != null) { // is a shared type reference which was already resolved + if (!this.resolvedType.isValidBinding()) { + return null; // already reported error + } + } + else { + if (this.argument != null) { + TypeReference typeRef = this.argument.type; + if (typeRef != null) { + this.resolvedType = typeRef.getTypeBinding(scope); + typeRef.resolvedType = this.resolvedType; + if (!this.resolvedType.isValidBinding()) { + scope.problemReporter().javadocInvalidType(typeRef, this.resolvedType, scope.getDeclarationModifiers()); + return null; + } + if (isTypeUseDeprecated(this.resolvedType, scope)) { + scope.problemReporter().javadocDeprecatedType(this.resolvedType, typeRef, scope.getDeclarationModifiers()); + return null; + } + return this.resolvedType; + } + } + } + return null; + } + + public StringBuffer printExpression(int indent, StringBuffer output) { + if (this.argument == null) { + if (this.token != null) { + output.append(this.token); + } + } + else { + this.argument.print(indent, output); + } + return output; + } + + public void resolve(BlockScope scope) { + if (this.argument != null) { + this.argument.resolve(scope); + } + } + + public TypeBinding resolveType(BlockScope scope) { + return internalResolveType(scope); + } + + public TypeBinding resolveType(ClassScope scope) { + return internalResolveType(scope); + } + + /* (non-Javadoc) + * Redefine to capture javadoc specific signatures + * @see org.eclipse.jdt.internal.compiler.ast.ASTNode#traverse(org.eclipse.jdt.internal.compiler.ASTVisitor, org.eclipse.jdt.internal.compiler.lookup.BlockScope) + */ + public void traverse(ASTVisitor visitor, BlockScope blockScope) { + if (visitor.visit(this, blockScope)) { + if (this.argument != null) { + this.argument.traverse(visitor, blockScope); + } + } + visitor.endVisit(this, blockScope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/JavadocArrayQualifiedTypeReference.java b/src/java/org/eclipse/jdt/internal/compiler/ast/JavadocArrayQualifiedTypeReference.java new file mode 100644 index 0000000..86b4d0e --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/JavadocArrayQualifiedTypeReference.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.lookup.BlockScope; +import org.eclipse.jdt.internal.compiler.lookup.Scope; + + + +public class JavadocArrayQualifiedTypeReference extends ArrayQualifiedTypeReference { + + public int tagSourceStart, tagSourceEnd; + + public JavadocArrayQualifiedTypeReference(JavadocQualifiedTypeReference typeRef, int dim) { + super(typeRef.tokens, dim, typeRef.sourcePositions); + } + + protected void reportInvalidType(Scope scope) { + scope.problemReporter().javadocInvalidType(this, this.resolvedType, scope.getDeclarationModifiers()); + } + protected void reportDeprecatedType(Scope scope) { + scope.problemReporter().javadocDeprecatedType(this.resolvedType, this, scope.getDeclarationModifiers()); + } + + /* (non-Javadoc) + * Redefine to capture javadoc specific signatures + * @see org.eclipse.jdt.internal.compiler.ast.ASTNode#traverse(org.eclipse.jdt.internal.compiler.ASTVisitor, org.eclipse.jdt.internal.compiler.lookup.BlockScope) + */ + public void traverse(ASTVisitor visitor, BlockScope scope) { + visitor.visit(this, scope); + visitor.endVisit(this, scope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/JavadocArraySingleTypeReference.java b/src/java/org/eclipse/jdt/internal/compiler/ast/JavadocArraySingleTypeReference.java new file mode 100644 index 0000000..8395065 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/JavadocArraySingleTypeReference.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.lookup.BlockScope; +import org.eclipse.jdt.internal.compiler.lookup.Scope; + + +public class JavadocArraySingleTypeReference extends ArrayTypeReference { + + public JavadocArraySingleTypeReference(char[] name, int dim, long pos) { + super(name, dim, pos); + this.bits |= InsideJavadoc; + } + + protected void reportInvalidType(Scope scope) { + scope.problemReporter().javadocInvalidType(this, this.resolvedType, scope.getDeclarationModifiers()); + } + protected void reportDeprecatedType(Scope scope) { + scope.problemReporter().javadocDeprecatedType(this.resolvedType, this, scope.getDeclarationModifiers()); + } + + /* (non-Javadoc) + * Redefine to capture javadoc specific signatures + * @see org.eclipse.jdt.internal.compiler.ast.ASTNode#traverse(org.eclipse.jdt.internal.compiler.ASTVisitor, org.eclipse.jdt.internal.compiler.lookup.BlockScope) + */ + public void traverse(ASTVisitor visitor, BlockScope scope) { + visitor.visit(this, scope); + visitor.endVisit(this, scope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/JavadocFieldReference.java b/src/java/org/eclipse/jdt/internal/compiler/ast/JavadocFieldReference.java new file mode 100644 index 0000000..04f1016 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/JavadocFieldReference.java @@ -0,0 +1,130 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class JavadocFieldReference extends FieldReference { + + public int tagSourceStart, tagSourceEnd; + + public JavadocFieldReference(char[] source, long pos) { + super(source, pos); + this.bits |= InsideJavadoc; + } + + /* + * Resolves type on a Block or Class scope. + */ + private TypeBinding internalResolveType(Scope scope) { + + this.constant = NotAConstant; + if (this.receiver == null) { + this.receiverType = scope.enclosingSourceType(); + } else if (scope.kind == Scope.CLASS_SCOPE) { + this.receiverType = this.receiver.resolveType((ClassScope) scope); + } else { + this.receiverType = this.receiver.resolveType((BlockScope)scope); + } + if (this.receiverType == null) { + return null; + } + + Binding fieldBinding = (this.receiver != null && this.receiver.isThis()) + ? scope.classScope().getBinding(this.token, this.bits & RestrictiveFlagMASK, this, true /*resolve*/) + : scope.getField(this.receiverType, this.token, this); + if (!fieldBinding.isValidBinding()) { + // implicit lookup may discover issues due to static/constructor contexts. javadoc must be resilient + switch (fieldBinding.problemId()) { + case ProblemReasons.NonStaticReferenceInConstructorInvocation: + case ProblemReasons.NonStaticReferenceInStaticContext: + case ProblemReasons.InheritedNameHidesEnclosingName : + FieldBinding closestMatch = ((ProblemFieldBinding)fieldBinding).closestMatch; + if (closestMatch != null) { + fieldBinding = closestMatch; // ignore problem if can reach target field through it + } + } + } + if (!fieldBinding.isValidBinding() || !(fieldBinding instanceof FieldBinding)) { + if (this.receiverType instanceof ReferenceBinding) { + ReferenceBinding refBinding = (ReferenceBinding) this.receiverType; + MethodBinding[] bindings = refBinding.getMethods(this.token); + if (bindings == null) { + scope.problemReporter().javadocInvalidField(this.sourceStart, this.sourceEnd, fieldBinding, this.receiverType, scope.getDeclarationModifiers()); + } else { + switch (bindings.length) { + case 0: + scope.problemReporter().javadocInvalidField(this.sourceStart, this.sourceEnd, fieldBinding, this.receiverType, scope.getDeclarationModifiers()); + break; + case 1: + this.binding = null; + break; + default: + scope.problemReporter().javadocAmbiguousMethodReference(this.sourceStart, this.sourceEnd, fieldBinding, scope.getDeclarationModifiers()); + break; + } + } + } + return null; + } + this.binding = (FieldBinding) fieldBinding; + + if (isFieldUseDeprecated(this.binding, scope, (this.bits & IsStrictlyAssignedMASK) != 0)) { + scope.problemReporter().javadocDeprecatedField(this.binding, this, scope.getDeclarationModifiers()); + } + return this.resolvedType = this.binding.type; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#isSuperAccess() + */ + public boolean isSuperAccess() { + return false; + } + + public StringBuffer printExpression(int indent, StringBuffer output) { + + if (this.receiver != null) { + this.receiver.printExpression(0, output); + } + output.append('#').append(this.token); + return output; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.ast.Expression#resolveType(org.eclipse.jdt.internal.compiler.lookup.BlockScope) + */ + public TypeBinding resolveType(BlockScope scope) { + return internalResolveType(scope); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.ast.Expression#resolveType(org.eclipse.jdt.internal.compiler.lookup.BlockScope) + */ + public TypeBinding resolveType(ClassScope scope) { + return internalResolveType(scope); + } + + /* (non-Javadoc) + * Redefine to capture javadoc specific signatures + * @see org.eclipse.jdt.internal.compiler.ast.ASTNode#traverse(org.eclipse.jdt.internal.compiler.ASTVisitor, org.eclipse.jdt.internal.compiler.lookup.BlockScope) + */ + public void traverse(ASTVisitor visitor, BlockScope scope) { + + if (visitor.visit(this, scope)) { + if (this.receiver != null) { + this.receiver.traverse(visitor, scope); + } + } + visitor.endVisit(this, scope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/JavadocImportReference.java b/src/java/org/eclipse/jdt/internal/compiler/ast/JavadocImportReference.java new file mode 100644 index 0000000..2f6d5b0 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/JavadocImportReference.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +/** + */ +public class JavadocImportReference extends ImportReference { + + public int tagSourceStart, tagSourceEnd; + + /** + * @param tokens + * @param sourcePositions + * @param tagStart + * @param tagEnd + */ + public JavadocImportReference(char[][] tokens, long[] sourcePositions, int tagStart, int tagEnd) { + super(tokens, sourcePositions, false, AccDefault); + this.tagSourceStart = tagStart; + this.tagSourceEnd = tagEnd; + this.bits |= InsideJavadoc; + } + +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/JavadocMessageSend.java b/src/java/org/eclipse/jdt/internal/compiler/ast/JavadocMessageSend.java new file mode 100644 index 0000000..ec69136 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/JavadocMessageSend.java @@ -0,0 +1,169 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.lookup.*; + + +public class JavadocMessageSend extends MessageSend { + + public int tagSourceStart, tagSourceEnd; + public boolean superAccess = false; + + public JavadocMessageSend(char[] name, long pos) { + this.selector = name; + this.nameSourcePosition = pos; + this.sourceStart = (int) (this.nameSourcePosition >>> 32); + this.sourceEnd = (int) this.nameSourcePosition; + this.bits |= InsideJavadoc; + } + public JavadocMessageSend(char[] name, long pos, JavadocArgumentExpression[] arguments) { + this(name, pos); + this.arguments = arguments; + } + + /* + * Resolves type on a Block or Class scope. + */ + private TypeBinding internalResolveType(Scope scope) { + // Answer the signature return type + // Base type promotion + this.constant = NotAConstant; + if (this.receiver == null) { + this.receiverType = scope.enclosingSourceType(); + } else if (scope.kind == Scope.CLASS_SCOPE) { + this.receiverType = this.receiver.resolveType((ClassScope) scope); + } else { + this.receiverType = this.receiver.resolveType((BlockScope) scope); + } + + // will check for null after args are resolved + TypeBinding[] argumentTypes = NoParameters; + if (this.arguments != null) { + boolean argHasError = false; // typeChecks all arguments + int length = this.arguments.length; + argumentTypes = new TypeBinding[length]; + for (int i = 0; i < length; i++){ + Expression argument = this.arguments[i]; + if (scope.kind == Scope.CLASS_SCOPE) { + argumentTypes[i] = argument.resolveType((ClassScope)scope); + } else { + argumentTypes[i] = argument.resolveType((BlockScope)scope); + } + if (argumentTypes[i] == null) { + argHasError = true; + } + } + if (argHasError) { + return null; + } + } + + // check receiver type + if (this.receiverType == null) { + return null; + } + this.qualifyingType = this.receiverType; + this.superAccess = scope.enclosingSourceType().isCompatibleWith(this.receiverType); + + // base type cannot receive any message + if (this.receiverType.isBaseType()) { + scope.problemReporter().javadocErrorNoMethodFor(this, this.receiverType, argumentTypes, scope.getDeclarationModifiers()); + return null; + } + this.binding = (this.receiver != null && this.receiver.isThis()) + ? scope.getImplicitMethod(this.selector, argumentTypes, this) + : scope.getMethod(this.receiverType, this.selector, argumentTypes, this); + if (!this.binding.isValidBinding()) { + // implicit lookup may discover issues due to static/constructor contexts. javadoc must be resilient + switch (this.binding.problemId()) { + case ProblemReasons.NonStaticReferenceInConstructorInvocation: + case ProblemReasons.NonStaticReferenceInStaticContext: + case ProblemReasons.InheritedNameHidesEnclosingName : + MethodBinding closestMatch = ((ProblemMethodBinding)this.binding).closestMatch; + if (closestMatch != null) { + this.binding = closestMatch; // ignore problem if can reach target method through it + } + } + } + if (!this.binding.isValidBinding()) { + if (this.binding.declaringClass == null) { + if (this.receiverType instanceof ReferenceBinding) { + this.binding.declaringClass = (ReferenceBinding) this.receiverType; + } else { + scope.problemReporter().javadocErrorNoMethodFor(this, this.receiverType, argumentTypes, scope.getDeclarationModifiers()); + return null; + } + } + scope.problemReporter().javadocInvalidMethod(this, this.binding, scope.getDeclarationModifiers()); + // record the closest match, for clients who may still need hint about possible method match + if (this.binding instanceof ProblemMethodBinding){ + MethodBinding closestMatch = ((ProblemMethodBinding)this.binding).closestMatch; + if (closestMatch != null) this.codegenBinding = this.binding = closestMatch; + } + return this.resolvedType = this.binding == null ? null : this.binding.returnType; + } + if (isMethodUseDeprecated(this.binding, scope)) { + scope.problemReporter().javadocDeprecatedMethod(this.binding, this, scope.getDeclarationModifiers()); + } + + return this.resolvedType = this.binding.returnType; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#isSuperAccess() + */ + public boolean isSuperAccess() { + return this.superAccess; + } + + public StringBuffer printExpression(int indent, StringBuffer output){ + + if (this.receiver != null) { + this.receiver.printExpression(0, output); + } + output.append('#').append(this.selector).append('('); + if (this.arguments != null) { + for (int i = 0; i < this.arguments.length ; i ++) { + if (i > 0) output.append(", "); //$NON-NLS-1$ + this.arguments[i].printExpression(0, output); + } + } + return output.append(')'); + } + + public TypeBinding resolveType(BlockScope scope) { + return internalResolveType(scope); + } + + public TypeBinding resolveType(ClassScope scope) { + return internalResolveType(scope); + } + + /* (non-Javadoc) + * Redefine to capture javadoc specific signatures + * @see org.eclipse.jdt.internal.compiler.ast.ASTNode#traverse(org.eclipse.jdt.internal.compiler.ASTVisitor, org.eclipse.jdt.internal.compiler.lookup.BlockScope) + */ + public void traverse(ASTVisitor visitor, BlockScope blockScope) { + if (visitor.visit(this, blockScope)) { + if (this.receiver != null) { + this.receiver.traverse(visitor, blockScope); + } + if (this.arguments != null) { + int argumentsLength = this.arguments.length; + for (int i = 0; i < argumentsLength; i++) + this.arguments[i].traverse(visitor, blockScope); + } + } + visitor.endVisit(this, blockScope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/JavadocQualifiedTypeReference.java b/src/java/org/eclipse/jdt/internal/compiler/ast/JavadocQualifiedTypeReference.java new file mode 100644 index 0000000..388f8ef --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/JavadocQualifiedTypeReference.java @@ -0,0 +1,93 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.lookup.Binding; +import org.eclipse.jdt.internal.compiler.lookup.BlockScope; +import org.eclipse.jdt.internal.compiler.lookup.ClassScope; +import org.eclipse.jdt.internal.compiler.lookup.PackageBinding; +import org.eclipse.jdt.internal.compiler.lookup.Scope; +import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; + + + +public class JavadocQualifiedTypeReference extends QualifiedTypeReference { + + public int tagSourceStart, tagSourceEnd; + public PackageBinding packageBinding; + + public JavadocQualifiedTypeReference(char[][] sources, long[] pos, int tagStart, int tagEnd) { + super(sources, pos); + this.tagSourceStart = tagStart; + this.tagSourceEnd = tagEnd; + this.bits |= InsideJavadoc; + } + + protected void reportInvalidType(Scope scope) { + scope.problemReporter().javadocInvalidType(this, this.resolvedType, scope.getDeclarationModifiers()); + } + protected void reportDeprecatedType(Scope scope) { + scope.problemReporter().javadocDeprecatedType(this.resolvedType, this, scope.getDeclarationModifiers()); + } + + /* (non-Javadoc) + * Redefine to capture javadoc specific signatures + * @see org.eclipse.jdt.internal.compiler.ast.ASTNode#traverse(org.eclipse.jdt.internal.compiler.ASTVisitor, org.eclipse.jdt.internal.compiler.lookup.BlockScope) + */ + public void traverse(ASTVisitor visitor, BlockScope scope) { + visitor.visit(this, scope); + visitor.endVisit(this, scope); + } + + /* + * + */ + private TypeBinding internalResolveType(Scope scope) { + // handle the error here + this.constant = NotAConstant; + if (this.resolvedType != null) { // is a shared type reference which was already resolved + if (!this.resolvedType.isValidBinding()) + return null; // already reported error + } else { + this.resolvedType = getTypeBinding(scope); + if (!this.resolvedType.isValidBinding()) { + Binding binding = scope.getTypeOrPackage(this.tokens); + if (binding instanceof PackageBinding) { + this.packageBinding = (PackageBinding) binding; + } else { + reportInvalidType(scope); + } + return null; + } + if (isTypeUseDeprecated(this.resolvedType, scope)) { + reportDeprecatedType(scope); + } + } + return this.resolvedType; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.ast.Expression#resolveType(org.eclipse.jdt.internal.compiler.lookup.BlockScope) + * We need to override to handle package references + */ + public TypeBinding resolveType(BlockScope blockScope) { + return internalResolveType(blockScope); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.ast.Expression#resolveType(org.eclipse.jdt.internal.compiler.lookup.ClassScope) + * We need to override to handle package references + */ + public TypeBinding resolveType(ClassScope classScope) { + return internalResolveType(classScope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/JavadocReturnStatement.java b/src/java/org/eclipse/jdt/internal/compiler/ast/JavadocReturnStatement.java new file mode 100644 index 0000000..8a53e1b --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/JavadocReturnStatement.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.lookup.*; + + +public class JavadocReturnStatement extends ReturnStatement { + public char[] description; + + public JavadocReturnStatement(int s, int e, char[] descr) { + super(null, s, e); + this.description = descr; + this.bits |= InsideJavadoc; + } + + public void resolve(BlockScope scope) { + MethodScope methodScope = scope.methodScope(); + MethodBinding methodBinding; + TypeBinding methodType = + (methodScope.referenceContext instanceof AbstractMethodDeclaration) + ? ((methodBinding = ((AbstractMethodDeclaration) methodScope.referenceContext).binding) == null + ? null + : methodBinding.returnType) + : VoidBinding; + if (methodType == null || methodType == VoidBinding) { + scope.problemReporter().javadocUnexpectedTag(this.sourceStart, this.sourceEnd); + } + } + + /* (non-Javadoc) + * Redefine to capture javadoc specific signatures + * @see org.eclipse.jdt.internal.compiler.ast.ASTNode#traverse(org.eclipse.jdt.internal.compiler.ASTVisitor, org.eclipse.jdt.internal.compiler.lookup.BlockScope) + */ + public void traverse(ASTVisitor visitor, BlockScope scope) { + visitor.visit(this, scope); + visitor.endVisit(this, scope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/JavadocSingleNameReference.java b/src/java/org/eclipse/jdt/internal/compiler/ast/JavadocSingleNameReference.java new file mode 100644 index 0000000..5661217 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/JavadocSingleNameReference.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class JavadocSingleNameReference extends SingleNameReference { + + public int tagSourceStart, tagSourceEnd; + + public JavadocSingleNameReference(char[] name, int startPosition, int endPosition) { + super(name, (((long) startPosition) << 32) + endPosition); + this.bits |= InsideJavadoc; + } + + public void resolve(BlockScope scope) { + resolve(scope, true); + } + + /** + * Resolve without warnings + */ + public void resolve(BlockScope scope, boolean warn) { + + LocalVariableBinding variableBinding = scope.findVariable(this.token); + if (variableBinding != null && variableBinding.isValidBinding() && variableBinding.isArgument) { + this.binding = variableBinding; + return; + } + if (warn) { + try { + MethodScope methScope = (MethodScope) scope; + scope.problemReporter().javadocInvalidParamName(this, methScope.referenceMethod().modifiers); + } + catch (Exception e) { + scope.problemReporter().javadocInvalidParamName(this, -1); + } + } + } + + /* (non-Javadoc) + * Redefine to capture javadoc specific signatures + * @see org.eclipse.jdt.internal.compiler.ast.ASTNode#traverse(org.eclipse.jdt.internal.compiler.ASTVisitor, org.eclipse.jdt.internal.compiler.lookup.BlockScope) + */ + public void traverse(ASTVisitor visitor, BlockScope scope) { + visitor.visit(this, scope); + visitor.endVisit(this, scope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/JavadocSingleTypeReference.java b/src/java/org/eclipse/jdt/internal/compiler/ast/JavadocSingleTypeReference.java new file mode 100644 index 0000000..541f099 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/JavadocSingleTypeReference.java @@ -0,0 +1,93 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.lookup.Binding; +import org.eclipse.jdt.internal.compiler.lookup.BlockScope; +import org.eclipse.jdt.internal.compiler.lookup.ClassScope; +import org.eclipse.jdt.internal.compiler.lookup.PackageBinding; +import org.eclipse.jdt.internal.compiler.lookup.Scope; +import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; + + +public class JavadocSingleTypeReference extends SingleTypeReference { + + public int tagSourceStart, tagSourceEnd; + public PackageBinding packageBinding; + + public JavadocSingleTypeReference(char[] source, long pos, int tagStart, int tagEnd) { + super(source, pos); + this.tagSourceStart = tagStart; + this.tagSourceEnd = tagEnd; + this.bits |= InsideJavadoc; + } + + protected void reportInvalidType(Scope scope) { + scope.problemReporter().javadocInvalidType(this, this.resolvedType, scope.getDeclarationModifiers()); + } + protected void reportDeprecatedType(Scope scope) { + scope.problemReporter().javadocDeprecatedType(this.resolvedType, this, scope.getDeclarationModifiers()); + } + + /* (non-Javadoc) + * Redefine to capture javadoc specific signatures + * @see org.eclipse.jdt.internal.compiler.ast.ASTNode#traverse(org.eclipse.jdt.internal.compiler.ASTVisitor, org.eclipse.jdt.internal.compiler.lookup.BlockScope) + */ + public void traverse(ASTVisitor visitor, BlockScope scope) { + visitor.visit(this, scope); + visitor.endVisit(this, scope); + } + + /* + * + */ + private TypeBinding internalResolveType(Scope scope) { + // handle the error here + this.constant = NotAConstant; + if (this.resolvedType != null) { // is a shared type reference which was already resolved + if (!this.resolvedType.isValidBinding()) + return null; // already reported error + } else { + this.resolvedType = getTypeBinding(scope); + if (!this.resolvedType.isValidBinding()) { + char[][] tokens = { this.token }; + Binding binding = scope.getTypeOrPackage(tokens); + if (binding instanceof PackageBinding) { + this.packageBinding = (PackageBinding) binding; + } else { + reportInvalidType(scope); + } + return null; + } + if (isTypeUseDeprecated(this.resolvedType, scope)) { + reportDeprecatedType(scope); + } + } + return this.resolvedType; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.ast.Expression#resolveType(org.eclipse.jdt.internal.compiler.lookup.BlockScope) + * We need to override to handle package references + */ + public TypeBinding resolveType(BlockScope blockScope) { + return internalResolveType(blockScope); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.ast.Expression#resolveType(org.eclipse.jdt.internal.compiler.lookup.ClassScope) + * We need to override to handle package references + */ + public TypeBinding resolveType(ClassScope classScope) { + return internalResolveType(classScope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/LabeledStatement.java b/src/java/org/eclipse/jdt/internal/compiler/ast/LabeledStatement.java new file mode 100644 index 0000000..b24cde3 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/LabeledStatement.java @@ -0,0 +1,129 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class LabeledStatement extends Statement { + + public Statement statement; + public char[] label; + public Label targetLabel; + + // for local variables table attributes + int mergedInitStateIndex = -1; + + /** + * LabeledStatement constructor comment. + */ + public LabeledStatement(char[] label, Statement statement, int sourceStart, int sourceEnd) { + + this.statement = statement; + // remember useful empty statement + if (statement instanceof EmptyStatement) statement.bits |= IsUsefulEmptyStatementMASK; + this.label = label; + this.sourceStart = sourceStart; + this.sourceEnd = sourceEnd; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + // need to stack a context to store explicit label, answer inits in case of normal completion merged + // with those relative to the exit path from break statement occurring inside the labeled statement. + if (statement == null) { + return flowInfo; + } else { + LabelFlowContext labelContext; + FlowInfo mergedInfo = + statement + .analyseCode( + currentScope, + (labelContext = + new LabelFlowContext( + flowContext, + this, + label, + (targetLabel = new Label()), + currentScope)), + flowInfo) + .mergedWith(labelContext.initsOnBreak); + mergedInitStateIndex = + currentScope.methodScope().recordInitializationStates(mergedInfo); + return mergedInfo; + } + } + + public ASTNode concreteStatement() { + + // return statement.concreteStatement(); // for supporting nested labels: a:b:c: someStatement (see 21912) + return statement; + } + + /** + * Code generation for labeled statement + * + * may not need actual source positions recording + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + + int pc = codeStream.position; + if (targetLabel != null) { + targetLabel.initialize(codeStream); + if (statement != null) { + statement.generateCode(currentScope, codeStream); + } + targetLabel.place(); + } + // May loose some local variable initializations : affecting the local variable attributes + if (mergedInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables(currentScope, mergedInitStateIndex); + codeStream.addDefinitelyAssignedVariables(currentScope, mergedInitStateIndex); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public StringBuffer printStatement(int tab, StringBuffer output) { + + printIndent(tab, output).append(label).append(": "); //$NON-NLS-1$ + if (this.statement == null) + output.append(';'); + else + this.statement.printStatement(0, output); + return output; + } + + public void resolve(BlockScope scope) { + + if (this.statement != null) { + this.statement.resolve(scope); + } + } + + + public void traverse( + ASTVisitor visitor, + BlockScope blockScope) { + + if (visitor.visit(this, blockScope)) { + if (this.statement != null) this.statement.traverse(visitor, blockScope); + } + visitor.endVisit(this, blockScope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/Literal.java b/src/java/org/eclipse/jdt/internal/compiler/ast/Literal.java new file mode 100644 index 0000000..32aa623 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/Literal.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.flow.FlowContext; +import org.eclipse.jdt.internal.compiler.flow.FlowInfo; +import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public abstract class Literal extends Expression { + + public Literal(int s, int e) { + + sourceStart = s; + sourceEnd = e; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + return flowInfo; + } + + public abstract void computeConstant(); + + public abstract TypeBinding literalType(BlockScope scope); + + public StringBuffer printExpression(int indent, StringBuffer output){ + + return output.append(source()); + } + + public TypeBinding resolveType(BlockScope scope) { + // compute the real value, which must range its type's range + this.resolvedType = literalType(scope); + + // in case of error, constant did remain null + computeConstant(); + if (constant == null) { + scope.problemReporter().constantOutOfRange(this, this.resolvedType); + constant = Constant.NotAConstant; + } + return this.resolvedType; + } + + public abstract char[] source(); +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java b/src/java/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java new file mode 100644 index 0000000..353fc00 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java @@ -0,0 +1,221 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class LocalDeclaration extends AbstractVariableDeclaration { + + public LocalVariableBinding binding; + + public LocalDeclaration( + char[] name, + int sourceStart, + int sourceEnd) { + + this.name = name; + this.sourceStart = sourceStart; + this.sourceEnd = sourceEnd; + this.declarationEnd = sourceEnd; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + // record variable initialization if any + if (flowInfo.isReachable()) { + bits |= IsLocalDeclarationReachableMASK; // only set if actually reached + } + if (initialization == null) + return flowInfo; + + flowInfo = + initialization + .analyseCode(currentScope, flowContext, flowInfo) + .unconditionalInits(); + + // final int i = (i = 0); + // no need to complain since (i = 0) part will get the blame + //if (binding.isFinal() && flowInfo.isPotentiallyAssigned(binding)) { + // currentScope.problemReporter().duplicateInitializationOfFinalLocal(binding, this); + //} + + flowInfo.markAsDefinitelyAssigned(binding); + return flowInfo; + } + + public void checkModifiers() { + + //only potential valid modifier is <> + if (((modifiers & AccJustFlag) & ~AccFinal) != 0) + //AccModifierProblem -> other (non-visibility problem) + //AccAlternateModifierProblem -> duplicate modifier + //AccModifierProblem | AccAlternateModifierProblem -> visibility problem" + + modifiers = (modifiers & ~AccAlternateModifierProblem) | AccModifierProblem; + } + + /** + * Code generation for a local declaration: + * i.e. normal assignment to a local variable + unused variable handling + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + + // even if not reachable, variable must be added to visible if allocated (28298) + if (binding.resolvedPosition != -1) { + codeStream.addVisibleLocalVariable(binding); + } + if ((bits & IsReachableMASK) == 0) { + return; + } + int pc = codeStream.position; + Constant inlinedValue; + + // something to initialize? + if (initialization != null) { + // initialize to constant value? + if ((inlinedValue = initialization.constant) != NotAConstant) { + // forget initializing unused or final locals set to constant value (final ones are inlined) + if (binding.resolvedPosition != -1) { // may need to preserve variable + int initPC = codeStream.position; + codeStream.generateConstant(inlinedValue, initialization.implicitConversion); + codeStream.recordPositionsFrom(initPC, initialization.sourceStart); + codeStream.store(binding, false); + binding.recordInitializationStartPC(codeStream.position); + // codeStream.lastInitStateIndexWhenRemovingInits = -2; // reinitialize remove index + // codeStream.lastInitStateIndexWhenAddingInits = -2; // reinitialize add index + } + } else { // initializing to non-constant value + initialization.generateCode(currentScope, codeStream, true); + // if binding unused generate then discard the value + if (binding.resolvedPosition != -1) { + // 26903, need extra cast to store null in array local var + if (binding.type.isArrayType() + && (initialization.resolvedType == NullBinding // arrayLoc = null + || ((initialization instanceof CastExpression) // arrayLoc = (type[])null + && (((CastExpression)initialization).innermostCastedExpression().resolvedType == NullBinding)))){ + codeStream.checkcast(binding.type); + } + codeStream.store(binding, false); + if (binding.initializationCount == 0) { + /* Variable may have been initialized during the code initializing it + e.g. int i = (i = 1); + */ + binding.recordInitializationStartPC(codeStream.position); + // codeStream.lastInitStateIndexWhenRemovingInits = -2; // reinitialize remove index + // codeStream.lastInitStateIndexWhenAddingInits = -2; // reinitialize add index + } + } else { + if ((binding.type == LongBinding) || (binding.type == DoubleBinding)) { + codeStream.pop2(); + } else { + codeStream.pop(); + } + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public void resolve(BlockScope scope) { + + // create a binding and add it to the scope + TypeBinding typeBinding = type.resolveType(scope); + + checkModifiers(); + + if (typeBinding != null) { + if (typeBinding == VoidBinding) { + scope.problemReporter().variableTypeCannotBeVoid(this); + return; + } + if (typeBinding.isArrayType() && ((ArrayBinding) typeBinding).leafComponentType == VoidBinding) { + scope.problemReporter().variableTypeCannotBeVoidArray(this); + return; + } + } + + Binding existingVariable = scope.getBinding(name, BindingIds.VARIABLE, this, false /*do not resolve hidden field*/); + boolean shouldInsertInScope = true; + if (existingVariable != null && existingVariable.isValidBinding()){ + if (existingVariable instanceof LocalVariableBinding && this.hiddenVariableDepth == 0) { + shouldInsertInScope = false; + scope.problemReporter().redefineLocal(this); + } else { + scope.problemReporter().localVariableHiding(this, existingVariable, false); + } + } + + if (shouldInsertInScope) { + if ((modifiers & AccFinal)!= 0 && this.initialization == null) { + modifiers |= AccBlankFinal; + } + binding = new LocalVariableBinding(this, typeBinding, modifiers, false); + scope.addLocalVariable(binding); + binding.constant = NotAConstant; + // allow to recursivelly target the binding.... + // the correct constant is harmed if correctly computed at the end of this method + } + + if (typeBinding == null) { + if (initialization != null) + initialization.resolveType(scope); // want to report all possible errors + return; + } + + // store the constant for final locals + if (initialization != null) { + if (initialization instanceof ArrayInitializer) { + TypeBinding initializationType = initialization.resolveTypeExpecting(scope, typeBinding); + if (initializationType != null) { + ((ArrayInitializer) initialization).binding = (ArrayBinding) initializationType; + initialization.implicitWidening(typeBinding, initializationType); + } + } else { + TypeBinding initializationType = initialization.resolveType(scope); + if (initializationType != null) { + if (initialization.isConstantValueOfTypeAssignableToType(initializationType, typeBinding) + || (typeBinding.isBaseType() && BaseTypeBinding.isWidening(typeBinding.id, initializationType.id)) + || initializationType.isCompatibleWith(typeBinding)) + initialization.implicitWidening(typeBinding, initializationType); + else + scope.problemReporter().typeMismatchError(initializationType, typeBinding, this); + } + } + + // change the constant in the binding when it is final + // (the optimization of the constant propagation will be done later on) + // cast from constant actual type to variable type + if (binding != null) { + binding.constant = + binding.isFinal() + ? initialization.constant.castTo((typeBinding.id << 4) + initialization.constant.typeID()) + : NotAConstant; + } + } + } + + public void traverse(ASTVisitor visitor, BlockScope scope) { + + if (visitor.visit(this, scope)) { + type.traverse(visitor, scope); + if (initialization != null) + initialization.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/LongLiteral.java b/src/java/org/eclipse/jdt/internal/compiler/ast/LongLiteral.java new file mode 100644 index 0000000..70294b5 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/LongLiteral.java @@ -0,0 +1,141 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class LongLiteral extends NumberLiteral { + long value; + + static final Constant FORMAT_ERROR = new DoubleConstant(1.0/0.0); // NaN; + +public LongLiteral(char[] token, int s,int e) { + super(token, s,e); +} +public LongLiteral(char[] token, int s,int e, long value) { + this(token, s,e); + this.value = value; +} +public void computeConstant() { + //the overflow (when radix=10) is tested using the fact that + //the value should always grow during its computation + + int length = source.length - 1; //minus one because the last char is 'l' or 'L' + + long computedValue ; + if (source[0] == '0') + { if (length == 1) { constant = Constant.fromValue(0L); return; } + final int shift,radix; + int j ; + if ( (source[1] == 'x') | (source[1] == 'X') ) + { shift = 4 ; j = 2; radix = 16;} + else + { shift = 3 ; j = 1; radix = 8;} + int nbDigit = 0; + while (source[j]=='0') + { j++; //jump over redondant zero + if ( j == length) + { //watch for 0000000000000L + constant = Constant.fromValue(value = 0L); + return ;}} + + int digitValue ; + if ((digitValue = Character.digit(source[j++],radix)) < 0 ) + { constant = FORMAT_ERROR; return ;} + if (digitValue >= 8) nbDigit = 4; + else if (digitValue >= 4) nbDigit = 3; + else if (digitValue >= 2) nbDigit = 2; + else nbDigit = 1; //digitValue is not 0 + computedValue = digitValue ; + while (j 64) return /*constant stays null*/ ; + computedValue = (computedValue< computedValue) return /*constant stays null*/;}} + + constant = Constant.fromValue(value = computedValue); +} +/** + * Code generation for long literal + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ +public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { + int pc = codeStream.position; + if (valueRequired) + if ((implicitConversion >> 4) == T_long) + codeStream.generateInlinedValue(value); + else + codeStream.generateConstant(constant, implicitConversion); + codeStream.recordPositionsFrom(pc, this.sourceStart); +} +public TypeBinding literalType(BlockScope scope) { + return LongBinding; +} +public final boolean mayRepresentMIN_VALUE(){ + //a special autorized int literral is 9223372036854775808L + //which is ONE over the limit. This special case + //only is used in combinaison with - to denote + //the minimal value of int -9223372036854775808L + + return ((source.length == 20) && + (source[0] == '9') && + (source[1] == '2') && + (source[2] == '2') && + (source[3] == '3') && + (source[4] == '3') && + (source[5] == '7') && + (source[6] == '2') && + (source[7] == '0') && + (source[8] == '3') && + (source[9] == '6') && + (source[10] == '8') && + (source[11] == '5') && + (source[12] == '4') && + (source[13] == '7') && + (source[14] == '7') && + (source[15] == '5') && + (source[16] == '8') && + (source[17] == '0') && + (source[18] == '8'));} +public TypeBinding resolveType(BlockScope scope) { + // the format may be incorrect while the scanner could detect + // such error only on painfull tests...easier and faster here + + TypeBinding tb = super.resolveType(scope); + if (constant == FORMAT_ERROR) { + constant = NotAConstant; + scope.problemReporter().constantOutOfFormat(this); + this.resolvedType = null; + return null; + } + return tb; +} +public void traverse(ASTVisitor visitor, BlockScope scope) { + visitor.visit(this, scope); + visitor.endVisit(this, scope); +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/LongLiteralMinValue.java b/src/java/org/eclipse/jdt/internal/compiler/ast/LongLiteralMinValue.java new file mode 100644 index 0000000..e24da63 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/LongLiteralMinValue.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.impl.*; + +public class LongLiteralMinValue extends LongLiteral { + + final static char[] CharValue = new char[]{'-', '9','2','2','3','3','7','2','0','3','6','8','5','4','7','7','5','8','0','8','L'}; + final static Constant MIN_VALUE = Constant.fromValue(Long.MIN_VALUE) ; + +public LongLiteralMinValue(){ + super(CharValue,0,0,Long.MIN_VALUE); + constant = MIN_VALUE; +} +public void computeConstant() { + + /*precomputed at creation time*/} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/MagicLiteral.java b/src/java/org/eclipse/jdt/internal/compiler/ast/MagicLiteral.java new file mode 100644 index 0000000..ed9b597 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/MagicLiteral.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +public abstract class MagicLiteral extends Literal { + + public MagicLiteral(int start , int end) { + + super(start,end); + } + + public boolean isValidJavaStatement(){ + + return false ; + } + + public char[] source() { + + return null; + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/MessageSend.java b/src/java/org/eclipse/jdt/internal/compiler/ast/MessageSend.java new file mode 100644 index 0000000..a9a2e9d --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/MessageSend.java @@ -0,0 +1,318 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Nick Teryaev - fix for bug (https://bugs.eclipse.org/bugs/show_bug.cgi?id=40752) + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class MessageSend extends Expression implements InvocationSite { + public Expression receiver ; + public char[] selector ; + public Expression[] arguments ; + public MethodBinding binding, codegenBinding; + + public long nameSourcePosition ; //(start<<32)+end + + MethodBinding syntheticAccessor; + + public TypeBinding receiverType, qualifyingType; + +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + + flowInfo = receiver.analyseCode(currentScope, flowContext, flowInfo, !binding.isStatic()).unconditionalInits(); + if (arguments != null) { + int length = arguments.length; + for (int i = 0; i < length; i++) { + flowInfo = arguments[i].analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); + } + } + ReferenceBinding[] thrownExceptions; + if ((thrownExceptions = binding.thrownExceptions) != NoExceptions) { + // must verify that exceptions potentially thrown by this expression are caught in the method + flowContext.checkExceptionHandlers(thrownExceptions, this, flowInfo, currentScope); + } + manageSyntheticAccessIfNecessary(currentScope, flowInfo); + return flowInfo; +} + +/** + * MessageSend code generation + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ +public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { + + int pc = codeStream.position; + + // generate receiver/enclosing instance access + boolean isStatic = codegenBinding.isStatic(); + // outer access ? + if (!isStatic && ((bits & DepthMASK) != 0) && receiver.isImplicitThis()){ + // outer method can be reached through emulation if implicit access + ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT); + Object[] path = currentScope.getEmulationPath(targetType, true /*only exact match*/, false/*consider enclosing arg*/); + codeStream.generateOuterAccess(path, this, targetType, currentScope); + } else { + receiver.generateCode(currentScope, codeStream, !isStatic); + } + // generate arguments + if (arguments != null){ + for (int i = 0, max = arguments.length; i < max; i++){ + arguments[i].generateCode(currentScope, codeStream, true); + } + } + // actual message invocation + if (syntheticAccessor == null){ + if (isStatic){ + codeStream.invokestatic(codegenBinding); + } else { + if( (receiver.isSuper()) || codegenBinding.isPrivate()){ + codeStream.invokespecial(codegenBinding); + } else { + if (codegenBinding.declaringClass.isInterface()){ + codeStream.invokeinterface(codegenBinding); + } else { + codeStream.invokevirtual(codegenBinding); + } + } + } + } else { + codeStream.invokestatic(syntheticAccessor); + } + // operation on the returned value + if (valueRequired){ + // implicit conversion if necessary + codeStream.generateImplicitConversion(implicitConversion); + } else { + // pop return value if any + switch(binding.returnType.id){ + case T_long : + case T_double : + codeStream.pop2(); + break; + case T_void : + break; + default: + codeStream.pop(); + } + } + codeStream.recordPositionsFrom(pc, (int)(this.nameSourcePosition >>> 32)); // highlight selector +} +public boolean isSuperAccess() { + return receiver.isSuper(); +} +public boolean isTypeAccess() { + return receiver != null && receiver.isTypeReference(); +} +public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo){ + + if (!flowInfo.isReachable()) return; + if (binding.isPrivate()){ + + // depth is set for both implicit and explicit access (see MethodBinding#canBeSeenBy) + if (currentScope.enclosingSourceType() != binding.declaringClass){ + + syntheticAccessor = ((SourceTypeBinding)binding.declaringClass).addSyntheticMethod(binding, isSuperAccess()); + currentScope.problemReporter().needToEmulateMethodAccess(binding, this); + return; + } + + } else if (receiver instanceof QualifiedSuperReference){ // qualified super + + // qualified super need emulation always + SourceTypeBinding destinationType = (SourceTypeBinding)(((QualifiedSuperReference)receiver).currentCompatibleType); + syntheticAccessor = destinationType.addSyntheticMethod(binding, isSuperAccess()); + currentScope.problemReporter().needToEmulateMethodAccess(binding, this); + return; + + } else if (binding.isProtected()){ + + SourceTypeBinding enclosingSourceType; + if (((bits & DepthMASK) != 0) + && binding.declaringClass.getPackage() + != (enclosingSourceType = currentScope.enclosingSourceType()).getPackage()){ + + SourceTypeBinding currentCompatibleType = (SourceTypeBinding)enclosingSourceType.enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT); + syntheticAccessor = currentCompatibleType.addSyntheticMethod(binding, isSuperAccess()); + currentScope.problemReporter().needToEmulateMethodAccess(binding, this); + return; + } + } + // if the binding declaring class is not visible, need special action + // for runtime compatibility on 1.2 VMs : change the declaring class of the binding + // NOTE: from target 1.2 on, method's declaring class is touched if any different from receiver type + // and not from Object or implicit static method call. + if (binding.declaringClass != this.qualifyingType + && !this.qualifyingType.isArrayType() + && ((currentScope.environment().options.targetJDK >= ClassFileConstants.JDK1_2 + && (!receiver.isImplicitThis() || !binding.isStatic()) + && binding.declaringClass.id != T_Object) // no change for Object methods + || !binding.declaringClass.canBeSeenBy(currentScope))) { + + this.codegenBinding = currentScope.enclosingSourceType().getUpdatedMethodBinding(binding, (ReferenceBinding) this.qualifyingType); + + // Post 1.4.0 target, array clone() invocations are qualified with array type + // This is handled in array type #clone method binding resolution (see Scope and UpdatedMethodBinding) + } +} + +public StringBuffer printExpression(int indent, StringBuffer output){ + + if (!receiver.isImplicitThis()) receiver.printExpression(0, output).append('.'); + output.append(selector).append('(') ; //$NON-NLS-1$ + if (arguments != null) { + for (int i = 0; i < arguments.length ; i ++) { + if (i > 0) output.append(", "); //$NON-NLS-1$ + arguments[i].printExpression(0, output); + } + } + return output.append(')'); +} + +public TypeBinding resolveType(BlockScope scope) { + // Answer the signature return type + // Base type promotion + + constant = NotAConstant; + boolean receiverCast = false, argumentsCast = false; + if (this.receiver instanceof CastExpression) { + this.receiver.bits |= IgnoreNeedForCastCheckMASK; // will check later on + receiverCast = true; + } + this.qualifyingType = this.receiverType = receiver.resolveType(scope); + if (receiverCast && this.receiverType != null) { + // due to change of declaring class with receiver type, only identity cast should be notified + if (((CastExpression)this.receiver).expression.resolvedType == this.receiverType) { + scope.problemReporter().unnecessaryCast((CastExpression)this.receiver); + } + } + // will check for null after args are resolved + TypeBinding[] argumentTypes = NoParameters; + if (arguments != null) { + boolean argHasError = false; // typeChecks all arguments + int length = arguments.length; + argumentTypes = new TypeBinding[length]; + for (int i = 0; i < length; i++){ + Expression argument = arguments[i]; + if (argument instanceof CastExpression) { + argument.bits |= IgnoreNeedForCastCheckMASK; // will check later on + argumentsCast = true; + } + if ((argumentTypes[i] = argument.resolveType(scope)) == null){ + argHasError = true; + } + } + if (argHasError) { + if(receiverType instanceof ReferenceBinding) { + // record any selector match, for clients who may still need hint about possible method match + this.codegenBinding = this.binding = scope.findMethod((ReferenceBinding)receiverType, selector, new TypeBinding[]{}, this); + } + return null; + } + } + if (this.receiverType == null) + return null; + + // base type cannot receive any message + if (this.receiverType.isBaseType()) { + scope.problemReporter().errorNoMethodFor(this, this.receiverType, argumentTypes); + return null; + } + this.codegenBinding = this.binding = + receiver.isImplicitThis() + ? scope.getImplicitMethod(selector, argumentTypes, this) + : scope.getMethod(this.receiverType, selector, argumentTypes, this); + if (!binding.isValidBinding()) { + if (binding.declaringClass == null) { + if (this.receiverType instanceof ReferenceBinding) { + binding.declaringClass = (ReferenceBinding) this.receiverType; + } else { + scope.problemReporter().errorNoMethodFor(this, this.receiverType, argumentTypes); + return null; + } + } + scope.problemReporter().invalidMethod(this, binding); + // record the closest match, for clients who may still need hint about possible method match + if (binding instanceof ProblemMethodBinding){ + MethodBinding closestMatch = ((ProblemMethodBinding)binding).closestMatch; + if (closestMatch != null) this.codegenBinding = this.binding = closestMatch; + } + return this.resolvedType = this.binding == null ? null : this.binding.returnType; + } + if (!binding.isStatic()) { + // the "receiver" must not be a type, in other words, a NameReference that the TC has bound to a Type + if (receiver instanceof NameReference + && (((NameReference) receiver).bits & BindingIds.TYPE) != 0) { + scope.problemReporter().mustUseAStaticMethod(this, binding); + } + } else { + // static message invoked through receiver? legal but unoptimal (optional warning). + if (!(receiver.isImplicitThis() + || receiver.isSuper() + || (receiver instanceof NameReference + && (((NameReference) receiver).bits & BindingIds.TYPE) != 0))) { + scope.problemReporter().nonStaticAccessToStaticMethod(this, binding); + } + if (!receiver.isImplicitThis() && binding.declaringClass != receiverType) { + scope.problemReporter().indirectAccessToStaticMethod(this, binding); + } + } + if (arguments != null) { + for (int i = 0; i < arguments.length; i++) { + arguments[i].implicitWidening(binding.parameters[i], argumentTypes[i]); + } + if (argumentsCast) { + CastExpression.checkNeedForArgumentCasts(scope, this.receiver, receiverType, binding, this.arguments, argumentTypes, this); + } + } + //-------message send that are known to fail at compile time----------- + if (binding.isAbstract()) { + if (receiver.isSuper()) { + scope.problemReporter().cannotDireclyInvokeAbstractMethod(this, binding); + } + // abstract private methods cannot occur nor abstract static............ + } + if (isMethodUseDeprecated(binding, scope)) + scope.problemReporter().deprecatedMethod(binding, this); + + return this.resolvedType = binding.returnType; +} +public void setActualReceiverType(ReferenceBinding receiverType) { + this.qualifyingType = receiverType; +} +public void setDepth(int depth) { + bits &= ~DepthMASK; // flush previous depth if any + if (depth > 0) { + bits |= (depth & 0xFF) << DepthSHIFT; // encoded on 8 bits + } +} +public void setFieldIndex(int depth) { + // ignore for here +} + +public void traverse(ASTVisitor visitor, BlockScope blockScope) { + if (visitor.visit(this, blockScope)) { + receiver.traverse(visitor, blockScope); + if (arguments != null) { + int argumentsLength = arguments.length; + for (int i = 0; i < argumentsLength; i++) + arguments[i].traverse(visitor, blockScope); + } + } + visitor.endVisit(this, blockScope); +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java b/src/java/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java new file mode 100644 index 0000000..b738665 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java @@ -0,0 +1,165 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.core.compiler.*; +import org.eclipse.jdt.internal.compiler.CompilationResult; +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.flow.ExceptionHandlingFlowContext; +import org.eclipse.jdt.internal.compiler.flow.FlowInfo; +import org.eclipse.jdt.internal.compiler.flow.InitializationFlowContext; +import org.eclipse.jdt.internal.compiler.lookup.*; +import org.eclipse.jdt.internal.compiler.parser.*; +import org.eclipse.jdt.internal.compiler.problem.AbortMethod; + +public class MethodDeclaration extends AbstractMethodDeclaration { + + public TypeReference returnType; + + /** + * MethodDeclaration constructor comment. + */ + public MethodDeclaration(CompilationResult compilationResult) { + super(compilationResult); + } + + public void analyseCode( + ClassScope classScope, + InitializationFlowContext initializationContext, + FlowInfo flowInfo) { + + // starting of the code analysis for methods + if (ignoreFurtherInvestigation) + return; + try { + if (binding == null) + return; + + if (this.binding.isPrivate() && !this.binding.isPrivateUsed()) { + if (!classScope.referenceCompilationUnit().compilationResult.hasSyntaxError()) { + scope.problemReporter().unusedPrivateMethod(this); + } + } + + // may be in a non necessary for innerclass with static final constant fields + if (binding.isAbstract() || binding.isNative()) + return; + + ExceptionHandlingFlowContext methodContext = + new ExceptionHandlingFlowContext( + initializationContext, + this, + binding.thrownExceptions, + scope, + FlowInfo.DEAD_END); + + // propagate to statements + if (statements != null) { + boolean didAlreadyComplain = false; + for (int i = 0, count = statements.length; i < count; i++) { + Statement stat = statements[i]; + if (!stat.complainIfUnreachable(flowInfo, scope, didAlreadyComplain)) { + flowInfo = stat.analyseCode(scope, methodContext, flowInfo); + } else { + didAlreadyComplain = true; + } + } + } + // check for missing returning path + TypeBinding returnTypeBinding = binding.returnType; + if ((returnTypeBinding == VoidBinding) || isAbstract()) { + this.needFreeReturn = flowInfo.isReachable(); + } else { + if (flowInfo != FlowInfo.DEAD_END) { + scope.problemReporter().shouldReturn(returnTypeBinding, this); + } + } + // check unreachable catch blocks + methodContext.complainIfUnusedExceptionHandlers(this); + } catch (AbortMethod e) { + this.ignoreFurtherInvestigation = true; + } + } + + public void parseStatements(Parser parser, CompilationUnitDeclaration unit) { + + //fill up the method body with statement + if (ignoreFurtherInvestigation) + return; + parser.parse(this, unit); + } + + public StringBuffer printReturnType(int indent, StringBuffer output) { + + if (returnType == null) return output; + return returnType.printExpression(0, output).append(' '); + } + + public void resolveStatements() { + + // ========= abort on fatal error ============= + if (this.returnType != null && this.binding != null) { + this.returnType.resolvedType = this.binding.returnType; + // record the return type binding + } + // look if the name of the method is correct + if (binding != null && isTypeUseDeprecated(binding.returnType, scope)) + scope.problemReporter().deprecatedType(binding.returnType, returnType); + + // check if method with constructor name + if (CharOperation.equals(scope.enclosingSourceType().sourceName, selector)) { + scope.problemReporter().methodWithConstructorName(this); + } + + // by grammatical construction, interface methods are always abstract + if (!scope.enclosingSourceType().isInterface()){ + + // if a method has an semicolon body and is not declared as abstract==>error + // native methods may have a semicolon body + if ((modifiers & AccSemicolonBody) != 0) { + if ((modifiers & AccNative) == 0) + if ((modifiers & AccAbstract) == 0) + scope.problemReporter().methodNeedBody(this); + } else { + // the method HAS a body --> abstract native modifiers are forbiden + if (((modifiers & AccNative) != 0) || ((modifiers & AccAbstract) != 0)) + scope.problemReporter().methodNeedingNoBody(this); + } + } + super.resolveStatements(); + } + + public void traverse( + ASTVisitor visitor, + ClassScope classScope) { + + if (visitor.visit(this, classScope)) { + if (returnType != null) + returnType.traverse(visitor, scope); + if (arguments != null) { + int argumentLength = arguments.length; + for (int i = 0; i < argumentLength; i++) + arguments[i].traverse(visitor, scope); + } + if (thrownExceptions != null) { + int thrownExceptionsLength = thrownExceptions.length; + for (int i = 0; i < thrownExceptionsLength; i++) + thrownExceptions[i].traverse(visitor, scope); + } + if (statements != null) { + int statementsLength = statements.length; + for (int i = 0; i < statementsLength; i++) + statements[i].traverse(visitor, scope); + } + } + visitor.endVisit(this, classScope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/NameReference.java b/src/java/org/eclipse/jdt/internal/compiler/ast/NameReference.java new file mode 100644 index 0000000..98a3f30 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/NameReference.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.lookup.*; + +public abstract class NameReference extends Reference implements InvocationSite, BindingIds { + + public Binding binding, codegenBinding; //may be aTypeBinding-aFieldBinding-aLocalVariableBinding + + public TypeBinding receiverType; // raw receiver type + public TypeBinding actualReceiverType; // modified receiver type - actual one according to namelookup + + //the error printing + //some name reference are build as name reference but + //only used as type reference. When it happens, instead of + //creating a new objet (aTypeReference) we just flag a boolean + //This concesion is valuable while their are cases when the NameReference + //will be a TypeReference (static message sends.....) and there is + //no changeClass in java. +public NameReference() { + super(); + bits |= TYPE | VARIABLE; // restrictiveFlag + +} +public FieldBinding fieldBinding() { + //this method should be sent ONLY after a check against isFieldReference() + //check its use doing senders......... + + return (FieldBinding) binding ; +} +public boolean isSuperAccess() { + return false; +} +public boolean isTypeAccess() { + // null is acceptable when we are resolving the first part of a reference + return binding == null || binding instanceof ReferenceBinding; +} +public boolean isTypeReference() { + return binding instanceof ReferenceBinding; +} +public void setActualReceiverType(ReferenceBinding receiverType) { + this.actualReceiverType = receiverType; +} +public void setDepth(int depth) { + bits &= ~DepthMASK; // flush previous depth if any + if (depth > 0) { + bits |= (depth & 0xFF) << DepthSHIFT; // encoded on 8 bits + } +} +public void setFieldIndex(int index){ + // ignored +} + +public abstract String unboundReferenceErrorName(); +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/NullLiteral.java b/src/java/org/eclipse/jdt/internal/compiler/ast/NullLiteral.java new file mode 100644 index 0000000..d79b252 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/NullLiteral.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class NullLiteral extends MagicLiteral { + + static final char[] source = {'n' , 'u' , 'l' , 'l'}; + + public NullLiteral(int s , int e) { + + super(s,e); + } + + public void computeConstant() { + + constant = NotAConstant; + } + + /** + * Code generation for the null literal + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { + int pc = codeStream.position; + if (valueRequired) + codeStream.aconst_null(); + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + public TypeBinding literalType(BlockScope scope) { + return NullBinding; + } + + /** + * + */ + public char[] source() { + return source; + } + + public void traverse(ASTVisitor visitor, BlockScope scope) { + visitor.visit(this, scope); + visitor.endVisit(this, scope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/NumberLiteral.java b/src/java/org/eclipse/jdt/internal/compiler/ast/NumberLiteral.java new file mode 100644 index 0000000..62bea22 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/NumberLiteral.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +public abstract class NumberLiteral extends Literal { + + char[] source; + + public NumberLiteral(char[] token, int s, int e) { + + this(s,e) ; + source = token ; + } + + public NumberLiteral(int s, int e) { + super (s,e) ; + } + + public boolean isValidJavaStatement(){ + + return false ; + } + + public char[] source(){ + + return source; + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/OR_OR_Expression.java b/src/java/org/eclipse/jdt/internal/compiler/ast/OR_OR_Expression.java new file mode 100644 index 0000000..a544e53 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/OR_OR_Expression.java @@ -0,0 +1,272 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +//dedicated treatment for the || +public class OR_OR_Expression extends BinaryExpression { + + int rightInitStateIndex = -1; + int mergedInitStateIndex = -1; + + public OR_OR_Expression(Expression left, Expression right, int operator) { + super(left, right, operator); + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + Constant cst = this.left.optimizedBooleanConstant(); + boolean isLeftOptimizedTrue = cst != NotAConstant && cst.booleanValue() == true; + boolean isLeftOptimizedFalse = cst != NotAConstant && cst.booleanValue() == false; + + if (isLeftOptimizedFalse) { + // FALSE || anything + // need to be careful of scenario: + // (x || y) || !z, if passing the left info to the right, it would be swapped by the ! + FlowInfo mergedInfo = left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); + mergedInfo = right.analyseCode(currentScope, flowContext, mergedInfo); + mergedInitStateIndex = + currentScope.methodScope().recordInitializationStates(mergedInfo); + return mergedInfo; + } + + FlowInfo leftInfo = left.analyseCode(currentScope, flowContext, flowInfo); + + // need to be careful of scenario: + // (x || y) || !z, if passing the left info to the right, it would be swapped by the ! + FlowInfo rightInfo = leftInfo.initsWhenFalse().unconditionalInits().copy(); + rightInitStateIndex = + currentScope.methodScope().recordInitializationStates(rightInfo); + + int previousMode = rightInfo.reachMode(); + if (isLeftOptimizedTrue){ + rightInfo.setReachMode(FlowInfo.UNREACHABLE); + } + rightInfo = right.analyseCode(currentScope, flowContext, rightInfo); + FlowInfo falseMergedInfo = rightInfo.initsWhenFalse().copy(); + rightInfo.setReachMode(previousMode); // reset after falseMergedInfo got extracted + + FlowInfo mergedInfo = FlowInfo.conditional( + // merging two true initInfos for such a negative case: if ((t && (b = t)) || f) r = b; // b may not have been initialized + leftInfo.initsWhenTrue().copy().unconditionalInits().mergedWith( + rightInfo.initsWhenTrue().copy().unconditionalInits()), + falseMergedInfo); + mergedInitStateIndex = + currentScope.methodScope().recordInitializationStates(mergedInfo); + return mergedInfo; + } + + /** + * Code generation for a binary operation + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { + + int pc = codeStream.position; + if (constant != Constant.NotAConstant) { + // inlined value + if (valueRequired) + codeStream.generateConstant(constant, implicitConversion); + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + Constant cst = right.constant; + if (cst != NotAConstant) { + // || true --> true + if (cst.booleanValue() == true) { + this.left.generateCode(currentScope, codeStream, false); + if (valueRequired) codeStream.iconst_1(); + } else { + // || false --> + this.left.generateCode(currentScope, codeStream, valueRequired); + } + if (mergedInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables(currentScope, mergedInitStateIndex); + } + codeStream.generateImplicitConversion(implicitConversion); + codeStream.updateLastRecordedEndPC(codeStream.position); + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + + Label trueLabel = new Label(codeStream), endLabel; + cst = left.optimizedBooleanConstant(); + boolean leftIsConst = cst != NotAConstant; + boolean leftIsTrue = leftIsConst && cst.booleanValue() == true; + + cst = right.optimizedBooleanConstant(); + boolean rightIsConst = cst != NotAConstant; + boolean rightIsTrue = rightIsConst && cst.booleanValue() == true; + + generateOperands : { + if (leftIsConst) { + left.generateCode(currentScope, codeStream, false); + if (leftIsTrue) { + break generateOperands; // no need to generate right operand + } + } else { + left.generateOptimizedBoolean(currentScope, codeStream, trueLabel, null, true); + // need value, e.g. if (a == 1 || ((b = 2) > 0)) {} -> shouldn't initialize 'b' if a==1 + } + if (rightInitStateIndex != -1) { + codeStream.addDefinitelyAssignedVariables(currentScope, rightInitStateIndex); + } + if (rightIsConst) { + right.generateCode(currentScope, codeStream, false); + } else { + right.generateOptimizedBoolean(currentScope, codeStream, trueLabel, null, valueRequired); + } + } + if (mergedInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables(currentScope, mergedInitStateIndex); + } + /* + * improving code gen for such a case: boolean b = i < 0 || true since + * the label has never been used, we have the inlined value on the + * stack. + */ + if (valueRequired) { + if (leftIsConst && leftIsTrue) { + codeStream.iconst_1(); + codeStream.updateLastRecordedEndPC(codeStream.position); + } else { + if (rightIsConst && rightIsTrue) { + codeStream.iconst_1(); + codeStream.updateLastRecordedEndPC(codeStream.position); + } else { + codeStream.iconst_0(); + } + if (trueLabel.hasForwardReferences()) { + if ((bits & ValueForReturnMASK) != 0) { + codeStream.ireturn(); + trueLabel.place(); + codeStream.iconst_1(); + } else { + codeStream.goto_(endLabel = new Label(codeStream)); + codeStream.decrStackSize(1); + trueLabel.place(); + codeStream.iconst_1(); + endLabel.place(); + } + } else { + trueLabel.place(); + } + } + codeStream.generateImplicitConversion(implicitConversion); + codeStream.updateLastRecordedEndPC(codeStream.position); + } else { + trueLabel.place(); + } + } + + /** + * Boolean operator code generation Optimized operations are: || + */ + public void generateOptimizedBoolean(BlockScope currentScope, CodeStream codeStream, Label trueLabel, Label falseLabel, boolean valueRequired) { + + if (constant != Constant.NotAConstant) { + super.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired); + return; + } + + // || false --> + Constant cst = right.constant; + if (cst != NotAConstant && cst.booleanValue() == false) { + int pc = codeStream.position; + this.left.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired); + if (mergedInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables(currentScope, mergedInitStateIndex); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + + cst = left.optimizedBooleanConstant(); + boolean leftIsConst = cst != NotAConstant; + boolean leftIsTrue = leftIsConst && cst.booleanValue() == true; + + cst = right.optimizedBooleanConstant(); + boolean rightIsConst = cst != NotAConstant; + boolean rightIsTrue = rightIsConst && cst.booleanValue() == true; + + // default case + generateOperands : { + if (falseLabel == null) { + if (trueLabel != null) { + // implicit falling through the FALSE case + left.generateOptimizedBoolean(currentScope, codeStream, trueLabel, null, !leftIsConst); + // need value, e.g. if (a == 1 || ((b = 2) > 0)) {} -> shouldn't initialize 'b' if a==1 + if (leftIsConst && leftIsTrue) { + codeStream.goto_(trueLabel); + codeStream.updateLastRecordedEndPC(codeStream.position); + break generateOperands; // no need to generate right operand + } + if (rightInitStateIndex != -1) { + codeStream + .addDefinitelyAssignedVariables(currentScope, rightInitStateIndex); + } + right.generateOptimizedBoolean(currentScope, codeStream, trueLabel, null, valueRequired && !rightIsConst); + if (valueRequired && rightIsConst && rightIsTrue) { + codeStream.goto_(trueLabel); + codeStream.updateLastRecordedEndPC(codeStream.position); + } + } + } else { + // implicit falling through the TRUE case + if (trueLabel == null) { + Label internalTrueLabel = new Label(codeStream); + left.generateOptimizedBoolean(currentScope, codeStream, internalTrueLabel, null, !leftIsConst); + // need value, e.g. if (a == 1 || ((b = 2) > 0)) {} -> shouldn't initialize 'b' if a==1 + if (leftIsConst && leftIsTrue) { + internalTrueLabel.place(); + break generateOperands; // no need to generate right operand + } + if (rightInitStateIndex != -1) { + codeStream + .addDefinitelyAssignedVariables(currentScope, rightInitStateIndex); + } + right.generateOptimizedBoolean(currentScope, codeStream, null, falseLabel, valueRequired && !rightIsConst); + if (valueRequired && rightIsConst) { + if (!rightIsTrue) { + codeStream.goto_(falseLabel); + codeStream.updateLastRecordedEndPC(codeStream.position); + } + } + internalTrueLabel.place(); + } else { + // no implicit fall through TRUE/FALSE --> should never occur + } + } + } + if (mergedInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables(currentScope, mergedInitStateIndex); + } + } + + public boolean isCompactableOperation() { + return false; + } + + public void traverse(ASTVisitor visitor, BlockScope scope) { + if (visitor.visit(this, scope)) { + left.traverse(visitor, scope); + right.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/OperatorExpression.java b/src/java/org/eclipse/jdt/internal/compiler/ast/OperatorExpression.java new file mode 100644 index 0000000..4574e0b --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/OperatorExpression.java @@ -0,0 +1,1564 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +public abstract class OperatorExpression extends Expression implements OperatorIds { + + public static int[][] OperatorSignatures = new int[NumberOfTables][]; + + static {classInitialize();} + + /** + * OperatorExpression constructor comment. + */ + public OperatorExpression() { + super(); + } + public static final void classInitialize() { + OperatorSignatures[AND] = get_AND(); + OperatorSignatures[AND_AND] = get_AND_AND(); + OperatorSignatures[DIVIDE] = get_DIVIDE(); + OperatorSignatures[EQUAL_EQUAL] = get_EQUAL_EQUAL(); + OperatorSignatures[GREATER] = get_GREATER(); + OperatorSignatures[GREATER_EQUAL] = get_GREATER_EQUAL(); + OperatorSignatures[LEFT_SHIFT] = get_LEFT_SHIFT(); + OperatorSignatures[LESS] = get_LESS(); + OperatorSignatures[LESS_EQUAL] = get_LESS_EQUAL(); + OperatorSignatures[MINUS] = get_MINUS(); + OperatorSignatures[MULTIPLY] = get_MULTIPLY(); + OperatorSignatures[OR] = get_OR(); + OperatorSignatures[OR_OR] = get_OR_OR(); + OperatorSignatures[PLUS] = get_PLUS(); + OperatorSignatures[REMAINDER] = get_REMAINDER(); + OperatorSignatures[RIGHT_SHIFT] = get_RIGHT_SHIFT(); + OperatorSignatures[UNSIGNED_RIGHT_SHIFT] = get_UNSIGNED_RIGHT_SHIFT(); + OperatorSignatures[XOR] = get_XOR(); + } + + public static final String generateTableTestCase(){ + //return a String which is a java method allowing to test + //the non zero entries of all tables + + /* + org.eclipse.jdt.internal.compiler.ast. + OperatorExpression.generateTableTestCase(); + */ + + int[] operators = new int[]{AND,AND_AND,DIVIDE,GREATER,GREATER_EQUAL, + LEFT_SHIFT,LESS,LESS_EQUAL,MINUS,MULTIPLY,OR,OR_OR,PLUS,REMAINDER, + RIGHT_SHIFT,UNSIGNED_RIGHT_SHIFT,XOR}; + + class Decode { + public final String constant(int code){ + switch(code){ + case T_boolean : return "true"; //$NON-NLS-1$ + case T_byte : return "((byte) 3)"; //$NON-NLS-1$ + case T_char : return "'A'"; //$NON-NLS-1$ + case T_double : return "300.0d"; //$NON-NLS-1$ + case T_float : return "100.0f"; //$NON-NLS-1$ + case T_int : return "1"; //$NON-NLS-1$ + case T_long : return "7L"; //$NON-NLS-1$ + case T_String : return "\"hello-world\""; //$NON-NLS-1$ + case T_null : return "null"; //$NON-NLS-1$ + case T_short : return "((short) 5)"; //$NON-NLS-1$ + case T_Object : return "null";} //$NON-NLS-1$ + return "";} //$NON-NLS-1$ + + public final String type(int code){ + switch(code){ + case T_boolean : return "z"; //$NON-NLS-1$ + case T_byte : return "b"; //$NON-NLS-1$ + case T_char : return "c"; //$NON-NLS-1$ + case T_double : return "d"; //$NON-NLS-1$ + case T_float : return "f"; //$NON-NLS-1$ + case T_int : return "i"; //$NON-NLS-1$ + case T_long : return "l"; //$NON-NLS-1$ + case T_String : return "str"; //$NON-NLS-1$ + case T_null : return "null"; //$NON-NLS-1$ + case T_short : return "s"; //$NON-NLS-1$ + case T_Object : return "obj";} //$NON-NLS-1$ + return "xxx";} //$NON-NLS-1$ + + public final String operator(int operator){ + switch (operator) { + case EQUAL_EQUAL : return "=="; //$NON-NLS-1$ + case LESS_EQUAL : return "<="; //$NON-NLS-1$ + case GREATER_EQUAL :return ">="; //$NON-NLS-1$ + case LEFT_SHIFT : return "<<"; //$NON-NLS-1$ + case RIGHT_SHIFT : return ">>"; //$NON-NLS-1$ + case UNSIGNED_RIGHT_SHIFT : return ">>>"; //$NON-NLS-1$ + case OR_OR :return "||"; //$NON-NLS-1$ + case AND_AND : return "&&"; //$NON-NLS-1$ + case PLUS : return "+"; //$NON-NLS-1$ + case MINUS : return "-"; //$NON-NLS-1$ + case NOT : return "!"; //$NON-NLS-1$ + case REMAINDER : return "%"; //$NON-NLS-1$ + case XOR : return "^"; //$NON-NLS-1$ + case AND : return "&"; //$NON-NLS-1$ + case MULTIPLY : return "*"; //$NON-NLS-1$ + case OR : return "|"; //$NON-NLS-1$ + case TWIDDLE : return "~"; //$NON-NLS-1$ + case DIVIDE : return "/"; //$NON-NLS-1$ + case GREATER : return ">"; //$NON-NLS-1$ + case LESS : return "<"; } //$NON-NLS-1$ + return "????";} //$NON-NLS-1$ + } + + + Decode decode = new Decode(); + String s; + + s = "\tpublic static void binaryOperationTablesTestCase(){\n" + //$NON-NLS-1$ + + "\t\t//TC test : all binary operation (described in tables)\n"+ //$NON-NLS-1$ + "\t\t//method automatically generated by\n"+ //$NON-NLS-1$ + "\t\t//org.eclipse.jdt.internal.compiler.ast.OperatorExpression.generateTableTestCase();\n"+ //$NON-NLS-1$ + + "\t\tString str0;\t String str\t= "+decode.constant(T_String)+";\n"+ //$NON-NLS-1$ //$NON-NLS-2$ + "\t\tint i0;\t int i\t= "+decode.constant(T_int)+";\n"+ //$NON-NLS-1$ //$NON-NLS-2$ + "\t\tboolean z0;\t boolean z\t= "+decode.constant(T_boolean)+";\n"+ //$NON-NLS-1$ //$NON-NLS-2$ + "\t\tchar c0; \t char c\t= "+decode.constant(T_char)+";\n"+ //$NON-NLS-1$ //$NON-NLS-2$ + "\t\tfloat f0; \t float f\t= "+decode.constant(T_float)+";\n"+ //$NON-NLS-1$ //$NON-NLS-2$ + "\t\tdouble d0;\t double d\t= "+decode.constant(T_double)+";\n"+ //$NON-NLS-1$ //$NON-NLS-2$ + "\t\tbyte b0; \t byte b\t= "+decode.constant(T_byte)+";\n"+ //$NON-NLS-1$ //$NON-NLS-2$ + "\t\tshort s0; \t short s\t= "+decode.constant(T_short)+";\n"+ //$NON-NLS-1$ //$NON-NLS-2$ + "\t\tlong l0; \t long l\t= "+decode.constant(T_long)+";\n"+ //$NON-NLS-1$ //$NON-NLS-2$ + "\t\tObject obj0; \t Object obj\t= "+decode.constant(T_Object)+";\n"+ //$NON-NLS-1$ //$NON-NLS-2$ + "\n"; //$NON-NLS-1$ + + int error = 0; + for (int i=0; i < operators.length; i++) + { int operator = operators[i]; + for (int left=0; left<16;left++) + for (int right=0; right<16;right++) + { int result = (OperatorSignatures[operator][(left<<4)+right]) & 0x0000F; + if (result != T_undefined) + + //1/ First regular computation then 2/ comparaison + //with a compile time constant (generated by the compiler) + // z0 = s >= s; + // if ( z0 != (((short) 5) >= ((short) 5))) + // System.out.println(155); + + { s += "\t\t"+decode.type(result)+"0"+" = "+decode.type(left); //$NON-NLS-1$ //$NON-NLS-3$ //$NON-NLS-2$ + s += " "+decode.operator(operator)+" "+decode.type(right)+";\n"; //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-3$ + String begin = result == T_String ? "\t\tif (! " : "\t\tif ( "; //$NON-NLS-2$ //$NON-NLS-1$ + String test = result == T_String ? ".equals(" : " != ("; //$NON-NLS-2$ //$NON-NLS-1$ + s += begin +decode.type(result)+"0"+test //$NON-NLS-1$ + +decode.constant(left)+" " //$NON-NLS-1$ + +decode.operator(operator)+" " //$NON-NLS-1$ + +decode.constant(right)+"))\n"; //$NON-NLS-1$ + s += "\t\t\tSystem.out.println("+ (++error) +");\n"; //$NON-NLS-1$ //$NON-NLS-2$ + + } + } + } + + return s += "\n\t\tSystem.out.println(\"binary tables test : done\");}"; //$NON-NLS-1$ + } + + public static final int[] get_AND(){ + + //the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 + + int[] table = new int[16*16]; + + // table[(T_undefined<<4)+T_undefined] = T_undefined; + // table[(T_undefined<<4)+T_byte] = T_undefined; + // table[(T_undefined<<4)+T_long] = T_undefined; + // table[(T_undefined<<4)+T_short] = T_undefined; + // table[(T_undefined<<4)+T_void] = T_undefined; + // table[(T_undefined<<4)+T_String] = T_undefined; + // table[(T_undefined<<4)+T_Object] = T_undefined; + // table[(T_undefined<<4)+T_double] = T_undefined; + // table[(T_undefined<<4)+T_float] = T_undefined; + // table[(T_undefined<<4)+T_boolean] = T_undefined; + // table[(T_undefined<<4)+T_char] = T_undefined; + // table[(T_undefined<<4)+T_int] = T_undefined; + // table[(T_undefined<<4)+T_null] = T_undefined; + + // table[(T_byte<<4)+T_undefined] = T_undefined; + table[(T_byte<<4)+T_byte] = (Byte2Int<<12) +(Byte2Int<<4) +T_int; + table[(T_byte<<4)+T_long] = (Byte2Long<<12)+(Long2Long<<4)+T_long; + table[(T_byte<<4)+T_short] = (Byte2Int<<12) +(Short2Int<<4)+T_int; + // table[(T_byte<<4)+T_void] = T_undefined; + // table[(T_byte<<4)+T_String] = T_undefined; + // table[(T_byte<<4)+T_Object] = T_undefined; + // table[(T_byte<<4)+T_double] = T_undefined; + // table[(T_byte<<4)+T_float] = T_undefined; + // table[(T_byte<<4)+T_boolean] = T_undefined; + table[(T_byte<<4)+T_char] = (Byte2Int<<12) +(Char2Int<<4) +T_int; + table[(T_byte<<4)+T_int] = (Byte2Int<<12) +(Int2Int<<4) +T_int; + // table[(T_byte<<4)+T_null] = T_undefined; + + // table[(T_long<<4)+T_undefined] = T_undefined; + table[(T_long<<4)+T_byte] = (Long2Long<<12)+(Byte2Long<<4)+T_long; + table[(T_long<<4)+T_long] = (Long2Long<<12)+(Long2Long<<4)+T_long; + table[(T_long<<4)+T_short] = (Long2Long<<12)+(Short2Long<<4)+T_long; + // table[(T_long<<4)+T_void] = T_undefined; + // table[(T_long<<4)+T_String] = T_undefined; + // table[(T_long<<4)+T_Object] = T_undefined; + // table[(T_long<<4)+T_double] = T_undefined; + // table[(T_long<<4)+T_float] = T_undefined; + // table[(T_long<<4)+T_boolean] = T_undefined; + table[(T_long<<4)+T_char] = (Long2Long<<12)+(Char2Long<<4)+T_long; + table[(T_long<<4)+T_int] = (Long2Long<<12)+(Int2Long<<4)+T_long; + // table[(T_long<<4)+T_null] = T_undefined; + + // table[(T_short<<4)+T_undefined] = T_undefined; + table[(T_short<<4)+T_byte] = (Short2Int<<12)+(Byte2Int<<4)+T_int; + table[(T_short<<4)+T_long] = (Short2Long<<12)+(Long2Long<<4)+T_long; + table[(T_short<<4)+T_short] = (Short2Int<<12)+(Short2Int<<4)+T_int; + // table[(T_short<<4)+T_void] = T_undefined; + // table[(T_short<<4)+T_String] = T_undefined; + // table[(T_short<<4)+T_Object] = T_undefined; + // table[(T_short<<4)+T_double] = T_undefined; + // table[(T_short<<4)+T_float] = T_undefined; + // table[(T_short<<4)+T_boolean] = T_undefined; + table[(T_short<<4)+T_char] = (Short2Int<<12)+(Char2Int<<4)+T_int; + table[(T_short<<4)+T_int] = (Short2Int<<12)+(Int2Int<<4)+T_int; + // table[(T_short<<4)+T_null] = T_undefined; + + // table[(T_void<<4)+T_undefined] = T_undefined; + // table[(T_void<<4)+T_byte] = T_undefined; + // table[(T_void<<4)+T_long] = T_undefined; + // table[(T_void<<4)+T_short] = T_undefined; + // table[(T_void<<4)+T_void] = T_undefined; + // table[(T_void<<4)+T_String] = T_undefined; + // table[(T_void<<4)+T_Object] = T_undefined; + // table[(T_void<<4)+T_double] = T_undefined; + // table[(T_void<<4)+T_float] = T_undefined; + // table[(T_void<<4)+T_boolean] = T_undefined; + // table[(T_void<<4)+T_char] = T_undefined; + // table[(T_void<<4)+T_int] = T_undefined; + // table[(T_void<<4)+T_null] = T_undefined; + + // table[(T_String<<4)+T_undefined] = T_undefined; + // table[(T_String<<4)+T_byte] = T_undefined; + // table[(T_String<<4)+T_long] = T_undefined; + // table[(T_String<<4)+T_short] = T_undefined; + // table[(T_String<<4)+T_void] = T_undefined; + // table[(T_String<<4)+T_String] = T_undefined; + // table[(T_String<<4)+T_Object] = T_undefined; + // table[(T_String<<4)+T_double] = T_undefined; + // table[(T_String<<4)+T_float] = T_undefined; + // table[(T_String<<4)+T_boolean] = T_undefined; + // table[(T_String<<4)+T_char] = T_undefined; + // table[(T_String<<4)+T_int] = T_undefined; + // table[(T_String<<4)+T_null] = T_undefined; + + // table[(T_Object<<4)+T_undefined] = T_undefined; + // table[(T_Object<<4)+T_byte] = T_undefined; + // table[(T_Object<<4)+T_long] = T_undefined; + // table[(T_Object<<4)+T_short] = T_undefined; + // table[(T_Object<<4)+T_void] = T_undefined; + // table[(T_Object<<4)+T_String] = T_undefined; + // table[(T_Object<<4)+T_Object] = T_undefined; + // table[(T_Object<<4)+T_double] = T_undefined; + // table[(T_Object<<4)+T_float] = T_undefined; + // table[(T_Object<<4)+T_boolean] = T_undefined; + // table[(T_Object<<4)+T_char] = T_undefined; + // table[(T_Object<<4)+T_int] = T_undefined; + // table[(T_Object<<4)+T_null] = T_undefined; + + // table[(T_double<<4)+T_undefined] = T_undefined; + // table[(T_double<<4)+T_byte] = T_undefined; + // table[(T_double<<4)+T_long] = T_undefined; + // table[(T_double<<4)+T_short] = T_undefined; + // table[(T_double<<4)+T_void] = T_undefined; + // table[(T_double<<4)+T_String] = T_undefined; + // table[(T_double<<4)+T_Object] = T_undefined; + // table[(T_double<<4)+T_double] = T_undefined; + // table[(T_double<<4)+T_float] = T_undefined; + // table[(T_double<<4)+T_boolean] = T_undefined; + // table[(T_double<<4)+T_char] = T_undefined; + // table[(T_double<<4)+T_int] = T_undefined; + // table[(T_double<<4)+T_null] = T_undefined; + + // table[(T_float<<4)+T_undefined] = T_undefined; + // table[(T_float<<4)+T_byte] = T_undefined; + // table[(T_float<<4)+T_long] = T_undefined; + // table[(T_float<<4)+T_short] = T_undefined; + // table[(T_float<<4)+T_void] = T_undefined; + // table[(T_float<<4)+T_String] = T_undefined; + // table[(T_float<<4)+T_Object] = T_undefined; + // table[(T_float<<4)+T_double] = T_undefined; + // table[(T_float<<4)+T_float] = T_undefined; + // table[(T_float<<4)+T_boolean] = T_undefined; + // table[(T_float<<4)+T_char] = T_undefined; + // table[(T_float<<4)+T_int] = T_undefined; + // table[(T_float<<4)+T_null] = T_undefined; + + // table[(T_boolean<<4)+T_undefined] = T_undefined; + // table[(T_boolean<<4)+T_byte] = T_undefined; + // table[(T_boolean<<4)+T_long] = T_undefined; + // table[(T_boolean<<4)+T_short] = T_undefined; + // table[(T_boolean<<4)+T_void] = T_undefined; + // table[(T_boolean<<4)+T_String] = T_undefined; + // table[(T_boolean<<4)+T_Object] = T_undefined; + // table[(T_boolean<<4)+T_double] = T_undefined; + // table[(T_boolean<<4)+T_float] = T_undefined; + table[(T_boolean<<4)+T_boolean] = (Boolean2Boolean << 12)+(Boolean2Boolean << 4)+T_boolean; + // table[(T_boolean<<4)+T_char] = T_undefined; + // table[(T_boolean<<4)+T_int] = T_undefined; + // table[(T_boolean<<4)+T_null] = T_undefined; + + // table[(T_char<<4)+T_undefined] = T_undefined; + table[(T_char<<4)+T_byte] = (Char2Int<<12)+(Byte2Int<<4)+T_int; + table[(T_char<<4)+T_long] = (Char2Long<<12)+(Long2Long<<4)+T_long; + table[(T_char<<4)+T_short] = (Char2Int<<12)+(Short2Int<<4)+T_int; + // table[(T_char<<4)+T_void] = T_undefined; + // table[(T_char<<4)+T_String] = T_undefined; + // table[(T_char<<4)+T_Object] = T_undefined; + // table[(T_char<<4)+T_double] = T_undefined; + // table[(T_char<<4)+T_float] = T_undefined; + // table[(T_char<<4)+T_boolean] = T_undefined; + table[(T_char<<4)+T_char] = (Char2Int<<12)+(Char2Int<<4)+T_int; + table[(T_char<<4)+T_int] = (Char2Int<<12)+(Int2Int<<4)+T_int; + // table[(T_char<<4)+T_null] = T_undefined; + + // table[(T_int<<4)+T_undefined] = T_undefined; + table[(T_int<<4)+T_byte] = (Int2Int<<12)+(Byte2Int<<4)+T_int; + table[(T_int<<4)+T_long] = (Int2Long<<12)+(Long2Long<<4)+T_long; + table[(T_int<<4)+T_short] = (Int2Int<<12)+(Short2Int<<4)+T_int; + // table[(T_int<<4)+T_void] = T_undefined; + // table[(T_int<<4)+T_String] = T_undefined; + // table[(T_int<<4)+T_Object] = T_undefined; + // table[(T_int<<4)+T_double] = T_undefined; + // table[(T_int<<4)+T_float] = T_undefined; + // table[(T_int<<4)+T_boolean] = T_undefined; + table[(T_int<<4)+T_char] = (Int2Int<<12)+(Char2Int<<4)+T_int; + table[(T_int<<4)+T_int] = (Int2Int<<12)+(Int2Int<<4)+T_int; + // table[(T_int<<4)+T_null] = T_undefined; + + // table[(T_null<<4)+T_undefined] = T_undefined; + // table[(T_null<<4)+T_byte] = T_undefined; + // table[(T_null<<4)+T_long] = T_undefined; + // table[(T_null<<4)+T_short] = T_undefined; + // table[(T_null<<4)+T_void] = T_undefined; + // table[(T_null<<4)+T_String] = T_undefined; + // table[(T_null<<4)+T_Object] = T_undefined; + // table[(T_null<<4)+T_double] = T_undefined; + // table[(T_null<<4)+T_float] = T_undefined; + // table[(T_null<<4)+T_boolean] = T_undefined; + // table[(T_null<<4)+T_char] = T_undefined; + // table[(T_null<<4)+T_int] = T_undefined; + // table[(T_null<<4)+T_null] = T_undefined; + + return table; + } + + public static final int[] get_AND_AND(){ + + //the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 + + int[] table = new int[16*16]; + + // table[(T_undefined<<4)+T_undefined] = T_undefined; + // table[(T_undefined<<4)+T_byte] = T_undefined; + // table[(T_undefined<<4)+T_long] = T_undefined; + // table[(T_undefined<<4)+T_short] = T_undefined; + // table[(T_undefined<<4)+T_void] = T_undefined; + // table[(T_undefined<<4)+T_String] = T_undefined; + // table[(T_undefined<<4)+T_Object] = T_undefined; + // table[(T_undefined<<4)+T_double] = T_undefined; + // table[(T_undefined<<4)+T_float] = T_undefined; + // table[(T_undefined<<4)+T_boolean] = T_undefined; + // table[(T_undefined<<4)+T_char] = T_undefined; + // table[(T_undefined<<4)+T_int] = T_undefined; + // table[(T_undefined<<4)+T_null] = T_undefined; + + // table[(T_byte<<4)+T_undefined] = T_undefined; + // table[(T_byte<<4)+T_byte] = T_undefined; + // table[(T_byte<<4)+T_long] = T_undefined; + // table[(T_byte<<4)+T_short] = T_undefined; + // table[(T_byte<<4)+T_void] = T_undefined; + // table[(T_byte<<4)+T_String] = T_undefined; + // table[(T_byte<<4)+T_Object] = T_undefined; + // table[(T_byte<<4)+T_double] = T_undefined; + // table[(T_byte<<4)+T_float] = T_undefined; + // table[(T_byte<<4)+T_boolean] = T_undefined; + // table[(T_byte<<4)+T_char] = T_undefined; + // table[(T_byte<<4)+T_int] = T_undefined; + // table[(T_byte<<4)+T_null] = T_undefined; + + // table[(T_long<<4)+T_undefined] = T_undefined; + // table[(T_long<<4)+T_byte] = T_undefined; + // table[(T_long<<4)+T_long] = T_undefined; + // table[(T_long<<4)+T_short] = T_undefined; + // table[(T_long<<4)+T_void] = T_undefined; + // table[(T_long<<4)+T_String] = T_undefined; + // table[(T_long<<4)+T_Object] = T_undefined; + // table[(T_long<<4)+T_double] = T_undefined; + // table[(T_long<<4)+T_float] = T_undefined; + // table[(T_long<<4)+T_boolean] = T_undefined; + // table[(T_long<<4)+T_char] = T_undefined; + // table[(T_long<<4)+T_int] = T_undefined; + // table[(T_long<<4)+T_null] = T_undefined; + + // table[(T_short<<4)+T_undefined] = T_undefined; + // table[(T_short<<4)+T_byte] = T_undefined; + // table[(T_short<<4)+T_long] = T_undefined; + // table[(T_short<<4)+T_short] = T_undefined; + // table[(T_short<<4)+T_void] = T_undefined; + // table[(T_short<<4)+T_String] = T_undefined; + // table[(T_short<<4)+T_Object] = T_undefined; + // table[(T_short<<4)+T_double] = T_undefined; + // table[(T_short<<4)+T_float] = T_undefined; + // table[(T_short<<4)+T_boolean] = T_undefined; + // table[(T_short<<4)+T_char] = T_undefined; + // table[(T_short<<4)+T_int] = T_undefined; + // table[(T_short<<4)+T_null] = T_undefined; + + // table[(T_void<<4)+T_undefined] = T_undefined; + // table[(T_void<<4)+T_byte] = T_undefined; + // table[(T_void<<4)+T_long] = T_undefined; + // table[(T_void<<4)+T_short] = T_undefined; + // table[(T_void<<4)+T_void] = T_undefined; + // table[(T_void<<4)+T_String] = T_undefined; + // table[(T_void<<4)+T_Object] = T_undefined; + // table[(T_void<<4)+T_double] = T_undefined; + // table[(T_void<<4)+T_float] = T_undefined; + // table[(T_void<<4)+T_boolean] = T_undefined; + // table[(T_void<<4)+T_char] = T_undefined; + // table[(T_void<<4)+T_int] = T_undefined; + // table[(T_void<<4)+T_null] = T_undefined; + + // table[(T_String<<4)+T_undefined] = T_undefined; + // table[(T_String<<4)+T_byte] = T_undefined; + // table[(T_String<<4)+T_long] = T_undefined; + // table[(T_String<<4)+T_short] = T_undefined; + // table[(T_String<<4)+T_void] = T_undefined; + // table[(T_String<<4)+T_String] = T_undefined; + // table[(T_String<<4)+T_Object] = T_undefined; + // table[(T_String<<4)+T_double] = T_undefined; + // table[(T_String<<4)+T_float] = T_undefined; + // table[(T_String<<4)+T_boolean] = T_undefined; + // table[(T_String<<4)+T_char] = T_undefined; + // table[(T_String<<4)+T_int] = T_undefined; + // table[(T_String<<4)+T_null] = T_undefined; + + // table[(T_Object<<4)+T_undefined] = T_undefined; + // table[(T_Object<<4)+T_byte] = T_undefined; + // table[(T_Object<<4)+T_long] = T_undefined; + // table[(T_Object<<4)+T_short] = T_undefined; + // table[(T_Object<<4)+T_void] = T_undefined; + // table[(T_Object<<4)+T_String] = T_undefined; + // table[(T_Object<<4)+T_Object] = T_undefined; + // table[(T_Object<<4)+T_double] = T_undefined; + // table[(T_Object<<4)+T_float] = T_undefined; + // table[(T_Object<<4)+T_boolean] = T_undefined; + // table[(T_Object<<4)+T_char] = T_undefined; + // table[(T_Object<<4)+T_int] = T_undefined; + // table[(T_Object<<4)+T_null] = T_undefined; + + // table[(T_double<<4)+T_undefined] = T_undefined; + // table[(T_double<<4)+T_byte] = T_undefined; + // table[(T_double<<4)+T_long] = T_undefined; + // table[(T_double<<4)+T_short] = T_undefined; + // table[(T_double<<4)+T_void] = T_undefined; + // table[(T_double<<4)+T_String] = T_undefined; + // table[(T_double<<4)+T_Object] = T_undefined; + // table[(T_double<<4)+T_double] = T_undefined; + // table[(T_double<<4)+T_float] = T_undefined; + // table[(T_double<<4)+T_boolean] = T_undefined; + // table[(T_double<<4)+T_char] = T_undefined; + // table[(T_double<<4)+T_int] = T_undefined; + // table[(T_double<<4)+T_null] = T_undefined; + + // table[(T_float<<4)+T_undefined] = T_undefined; + // table[(T_float<<4)+T_byte] = T_undefined; + // table[(T_float<<4)+T_long] = T_undefined; + // table[(T_float<<4)+T_short] = T_undefined; + // table[(T_float<<4)+T_void] = T_undefined; + // table[(T_float<<4)+T_String] = T_undefined; + // table[(T_float<<4)+T_Object] = T_undefined; + // table[(T_float<<4)+T_double] = T_undefined; + // table[(T_float<<4)+T_float] = T_undefined; + // table[(T_float<<4)+T_boolean] = T_undefined; + // table[(T_float<<4)+T_char] = T_undefined; + // table[(T_float<<4)+T_int] = T_undefined; + // table[(T_float<<4)+T_null] = T_undefined; + + // table[(T_boolean<<4)+T_undefined] = T_undefined; + // table[(T_boolean<<4)+T_byte] = T_undefined; + // table[(T_boolean<<4)+T_long] = T_undefined; + // table[(T_boolean<<4)+T_short] = T_undefined; + // table[(T_boolean<<4)+T_void] = T_undefined; + // table[(T_boolean<<4)+T_String] = T_undefined; + // table[(T_boolean<<4)+T_Object] = T_undefined; + // table[(T_boolean<<4)+T_double] = T_undefined; + // table[(T_boolean<<4)+T_float] = T_undefined; + table[(T_boolean<<4)+T_boolean] = (Boolean2Boolean<<12)+(Boolean2Boolean<<4)+T_boolean; + // table[(T_boolean<<4)+T_char] = T_undefined; + // table[(T_boolean<<4)+T_int] = T_undefined; + // table[(T_boolean<<4)+T_null] = T_undefined; + + // table[(T_char<<4)+T_undefined] = T_undefined; + // table[(T_char<<4)+T_byte] = T_undefined; + // table[(T_char<<4)+T_long] = T_undefined; + // table[(T_char<<4)+T_short] = T_undefined; + // table[(T_char<<4)+T_void] = T_undefined; + // table[(T_char<<4)+T_String] = T_undefined; + // table[(T_char<<4)+T_Object] = T_undefined; + // table[(T_char<<4)+T_double] = T_undefined; + // table[(T_char<<4)+T_float] = T_undefined; + // table[(T_char<<4)+T_boolean] = T_undefined; + // table[(T_char<<4)+T_char] = T_undefined; + // table[(T_char<<4)+T_int] = T_undefined; + // table[(T_char<<4)+T_null] = T_undefined; + + // table[(T_int<<4)+T_undefined] = T_undefined; + // table[(T_int<<4)+T_byte] = T_undefined; + // table[(T_int<<4)+T_long] = T_undefined; + // table[(T_int<<4)+T_short] = T_undefined; + // table[(T_int<<4)+T_void] = T_undefined; + // table[(T_int<<4)+T_String] = T_undefined; + // table[(T_int<<4)+T_Object] = T_undefined; + // table[(T_int<<4)+T_double] = T_undefined; + // table[(T_int<<4)+T_float] = T_undefined; + // table[(T_int<<4)+T_boolean] = T_undefined; + // table[(T_int<<4)+T_char] = T_undefined; + // table[(T_int<<4)+T_int] = T_undefined; + // table[(T_int<<4)+T_null] = T_undefined; + + // table[(T_null<<4)+T_undefined] = T_undefined; + // table[(T_null<<4)+T_byte] = T_undefined; + // table[(T_null<<4)+T_long] = T_undefined; + // table[(T_null<<4)+T_short] = T_undefined; + // table[(T_null<<4)+T_void] = T_undefined; + // table[(T_null<<4)+T_String] = T_undefined; + // table[(T_null<<4)+T_Object] = T_undefined; + // table[(T_null<<4)+T_double] = T_undefined; + // table[(T_null<<4)+T_float] = T_undefined; + // table[(T_null<<4)+T_boolean] = T_undefined; + // table[(T_null<<4)+T_char] = T_undefined; + // table[(T_null<<4)+T_int] = T_undefined; + // table[(T_null<<4)+T_null] = T_undefined; + return table; + } + + public static final int[] get_DIVIDE(){ + + //the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 + + + // int[] table = new int[16*16]; + + return get_MINUS(); + } + + public static final int[] get_EQUAL_EQUAL(){ + + //the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 + + int[] table = new int[16*16]; + + // table[(T_undefined<<4)+T_undefined] = T_undefined; + // table[(T_undefined<<4)+T_byte] = T_undefined; + // table[(T_undefined<<4)+T_long] = T_undefined; + // table[(T_undefined<<4)+T_short] = T_undefined; + // table[(T_undefined<<4)+T_void] = T_undefined; + // table[(T_undefined<<4)+T_String] = T_undefined; + // table[(T_undefined<<4)+T_Object] = T_undefined; + // table[(T_undefined<<4)+T_double] = T_undefined; + // table[(T_undefined<<4)+T_float] = T_undefined; + // table[(T_undefined<<4)+T_boolean] = T_undefined; + // table[(T_undefined<<4)+T_char] = T_undefined; + // table[(T_undefined<<4)+T_int] = T_undefined; + // table[(T_undefined<<4)+T_null] = T_undefined; + + // table[(T_byte<<4)+T_undefined] = T_undefined; + table[(T_byte<<4)+T_byte] = (Byte2Int<<12)+(Byte2Int<<4)+T_boolean; + table[(T_byte<<4)+T_long] = (Byte2Long<<12)+(Long2Long<<4)+T_boolean; + table[(T_byte<<4)+T_short] = (Byte2Int<<12)+(Short2Int<<4)+T_boolean; + // table[(T_byte<<4)+T_void] = T_undefined; + // table[(T_byte<<4)+T_String] = T_undefined; + // table[(T_byte<<4)+T_Object] = T_undefined; + table[(T_byte<<4)+T_double] = (Byte2Double<<12)+(Double2Double<<4)+T_boolean; + table[(T_byte<<4)+T_float] = (Byte2Float<<12)+(Float2Float<<4)+T_boolean; + // table[(T_byte<<4)+T_boolean] = T_undefined; + table[(T_byte<<4)+T_char] = (Byte2Int<<12)+(Char2Int<<4)+T_boolean; + table[(T_byte<<4)+T_int] = (Byte2Int<<12)+(Int2Int<<4)+T_boolean; + // table[(T_byte<<4)+T_null] = T_undefined; + + // table[(T_long<<4)+T_undefined] = T_undefined; + table[(T_long<<4)+T_byte] = (Long2Long<<12)+(Byte2Long<<4)+T_boolean; + table[(T_long<<4)+T_long] = (Long2Long<<12)+(Long2Long<<4)+T_boolean; + table[(T_long<<4)+T_short] = (Long2Long<<12)+(Short2Long<<4)+T_boolean; + // table[(T_long<<4)+T_void] = T_undefined; + // table[(T_long<<4)+T_String] = T_undefined; + // table[(T_long<<4)+T_Object] = T_undefined; + table[(T_long<<4)+T_double] = (Long2Double<<12)+(Double2Double<<4)+T_boolean; + table[(T_long<<4)+T_float] = (Long2Float<<12)+(Float2Float<<4)+T_boolean; + // table[(T_long<<4)+T_boolean] = T_undefined; + table[(T_long<<4)+T_char] = (Long2Long<<12)+(Char2Long<<4)+T_boolean; + table[(T_long<<4)+T_int] = (Long2Long<<12)+(Int2Long<<4)+T_boolean; + // table[(T_long<<4)+T_null] = T_undefined; + + // table[(T_short<<4)+T_undefined] = T_undefined; + table[(T_short<<4)+T_byte] = (Short2Int<<12)+(Byte2Int<<4)+T_boolean; + table[(T_short<<4)+T_long] = (Short2Long<<12)+(Long2Long<<4)+T_boolean; + table[(T_short<<4)+T_short] = (Short2Int<<12)+(Short2Int<<4)+T_boolean; + // table[(T_short<<4)+T_void] = T_undefined; + // table[(T_short<<4)+T_String] = T_undefined; + // table[(T_short<<4)+T_Object] = T_undefined; + table[(T_short<<4)+T_double] = (Short2Double<<12)+(Double2Double<<4)+T_boolean; + table[(T_short<<4)+T_float] = (Short2Float<<12)+(Float2Float<<4)+T_boolean; + // table[(T_short<<4)+T_boolean] = T_undefined; + table[(T_short<<4)+T_char] = (Short2Int<<12)+(Char2Int<<4)+T_boolean; + table[(T_short<<4)+T_int] = (Short2Int<<12)+(Int2Int<<4)+T_boolean; + // table[(T_short<<4)+T_null] = T_undefined; + + // table[(T_void<<4)+T_undefined] = T_undefined; + // table[(T_void<<4)+T_byte] = T_undefined; + // table[(T_void<<4)+T_long] = T_undefined; + // table[(T_void<<4)+T_short] = T_undefined; + // table[(T_void<<4)+T_void] = T_undefined; + // table[(T_void<<4)+T_String] = T_undefined; + // table[(T_void<<4)+T_Object] = T_undefined; + // table[(T_void<<4)+T_double] = T_undefined; + // table[(T_void<<4)+T_float] = T_undefined; + // table[(T_void<<4)+T_boolean] = T_undefined; + // table[(T_void<<4)+T_char] = T_undefined; + // table[(T_void<<4)+T_int] = T_undefined; + // table[(T_void<<4)+T_null] = T_undefined; + + // table[(T_String<<4)+T_undefined] = T_undefined; + // table[(T_String<<4)+T_byte] = T_undefined; + // table[(T_String<<4)+T_long] = T_undefined; + // table[(T_String<<4)+T_short] = T_undefined; + // table[(T_String<<4)+T_void] = T_undefined; + table[(T_String<<4)+T_String] = /*String2Object String2Object*/ + (T_Object<<16)+(T_String<<12)+(T_Object<<8)+(T_String<<4)+T_boolean; + table[(T_String<<4)+T_Object] = /*String2Object Object2Object*/ + (T_Object<<16)+(T_String<<12)+(T_Object<<8)+(T_Object<<4)+T_boolean; + // table[(T_String<<4)+T_double] = T_undefined; + // table[(T_String<<4)+T_float] = T_undefined; + // table[(T_String<<4)+T_boolean] = T_undefined; + // table[(T_String<<4)+T_char] = T_undefined; + // table[(T_String<<4)+T_int] = T_undefined; + table[(T_String<<4)+T_null] = /*Object2String null2Object */ + (T_Object<<16)+(T_String<<12)+(T_Object<<8)+(T_null<<4)+T_boolean; + + // table[(T_Object<<4)+T_undefined] = T_undefined; + // table[(T_Object<<4)+T_byte] = T_undefined; + // table[(T_Object<<4)+T_long] = T_undefined; + // table[(T_Object<<4)+T_short] = T_undefined; + // table[(T_Object<<4)+T_void] = T_undefined; + table[(T_Object<<4)+T_String] = /*Object2Object String2Object*/ + (T_Object<<16)+(T_Object<<12)+(T_Object<<8)+(T_String<<4)+T_boolean; + table[(T_Object<<4)+T_Object] = /*Object2Object Object2Object*/ + (T_Object<<16)+(T_Object<<12)+(T_Object<<8)+(T_Object<<4)+T_boolean; + // table[(T_Object<<4)+T_double] = T_undefined; + // table[(T_Object<<4)+T_float] = T_undefined; + // table[(T_Object<<4)+T_boolean] = T_undefined; + // table[(T_Object<<4)+T_char] = T_undefined; + // table[(T_Object<<4)+T_int] = T_undefined; + table[(T_Object<<4)+T_null] = /*Object2Object null2Object*/ + (T_Object<<16)+(T_Object<<12)+(T_Object<<8)+(T_null<<4)+T_boolean; + + // table[(T_double<<4)+T_undefined] = T_undefined; + table[(T_double<<4)+T_byte] = (Double2Double<<12)+(Byte2Double<<4)+T_boolean; + table[(T_double<<4)+T_long] = (Double2Double<<12)+(Long2Double<<4)+T_boolean; + table[(T_double<<4)+T_short] = (Double2Double<<12)+(Short2Double<<4)+T_boolean; + // table[(T_double<<4)+T_void] = T_undefined; + // table[(T_double<<4)+T_String] = T_undefined; + // table[(T_double<<4)+T_Object] = T_undefined; + table[(T_double<<4)+T_double] = (Double2Double<<12)+(Double2Double<<4)+T_boolean; + table[(T_double<<4)+T_float] = (Double2Double<<12)+(Float2Double<<4)+T_boolean; + // table[(T_double<<4)+T_boolean] = T_undefined; + table[(T_double<<4)+T_char] = (Double2Double<<12)+(Char2Double<<4)+T_boolean; + table[(T_double<<4)+T_int] = (Double2Double<<12)+(Int2Double<<4)+T_boolean; + // table[(T_double<<4)+T_null] = T_undefined; + + // table[(T_float<<4)+T_undefined] = T_undefined; + table[(T_float<<4)+T_byte] = (Float2Float<<12)+(Byte2Float<<4)+T_boolean; + table[(T_float<<4)+T_long] = (Float2Float<<12)+(Long2Float<<4)+T_boolean; + table[(T_float<<4)+T_short] = (Float2Float<<12)+(Short2Float<<4)+T_boolean; + // table[(T_float<<4)+T_void] = T_undefined; + // table[(T_float<<4)+T_String] = T_undefined; + // table[(T_float<<4)+T_Object] = T_undefined; + table[(T_float<<4)+T_double] = (Float2Double<<12)+(Double2Double<<4)+T_boolean; + table[(T_float<<4)+T_float] = (Float2Float<<12)+(Float2Float<<4)+T_boolean; + // table[(T_float<<4)+T_boolean] = T_undefined; + table[(T_float<<4)+T_char] = (Float2Float<<12)+(Char2Float<<4)+T_boolean; + table[(T_float<<4)+T_int] = (Float2Float<<12)+(Int2Float<<4)+T_boolean; + // table[(T_float<<4)+T_null] = T_undefined; + + // table[(T_boolean<<4)+T_undefined] = T_undefined; + // table[(T_boolean<<4)+T_byte] = T_undefined; + // table[(T_boolean<<4)+T_long] = T_undefined; + // table[(T_boolean<<4)+T_short] = T_undefined; + // table[(T_boolean<<4)+T_void] = T_undefined; + // table[(T_boolean<<4)+T_String] = T_undefined; + // table[(T_boolean<<4)+T_Object] = T_undefined; + // table[(T_boolean<<4)+T_double] = T_undefined; + // table[(T_boolean<<4)+T_float] = T_undefined; + table[(T_boolean<<4)+T_boolean] = (Boolean2Boolean<<12)+(Boolean2Boolean<<4)+T_boolean; + // table[(T_boolean<<4)+T_char] = T_undefined; + // table[(T_boolean<<4)+T_int] = T_undefined; + // table[(T_boolean<<4)+T_null] = T_undefined; + + // table[(T_char<<4)+T_undefined] = T_undefined; + table[(T_char<<4)+T_byte] = (Char2Int<<12)+(Byte2Int<<4)+T_boolean; + table[(T_char<<4)+T_long] = (Char2Long<<12)+(Long2Long<<4)+T_boolean; + table[(T_char<<4)+T_short] = (Char2Int<<12)+(Short2Int<<4)+T_boolean; + // table[(T_char<<4)+T_void] = T_undefined; + // table[(T_char<<4)+T_String] = T_undefined; + // table[(T_char<<4)+T_Object] = T_undefined; + table[(T_char<<4)+T_double] = (Char2Double<<12)+(Double2Double<<4)+T_boolean; + table[(T_char<<4)+T_float] = (Char2Float<<12)+(Float2Float<<4)+T_boolean; + // table[(T_char<<4)+T_boolean] = T_undefined; + table[(T_char<<4)+T_char] = (Char2Int<<12)+(Char2Int<<4)+T_boolean; + table[(T_char<<4)+T_int] = (Char2Int<<12)+(Int2Int<<4)+T_boolean; + // table[(T_char<<4)+T_null] = T_undefined; + + // table[(T_int<<4)+T_undefined] = T_undefined; + table[(T_int<<4)+T_byte] = (Int2Int<<12)+(Byte2Int<<4)+T_boolean; + table[(T_int<<4)+T_long] = (Int2Long<<12)+(Long2Long<<4)+T_boolean; + table[(T_int<<4)+T_short] = (Int2Int<<12)+(Short2Int<<4)+T_boolean; + // table[(T_int<<4)+T_void] = T_undefined; + // table[(T_int<<4)+T_String] = T_undefined; + // table[(T_int<<4)+T_Object] = T_undefined; + table[(T_int<<4)+T_double] = (Int2Double<<12)+(Double2Double<<4)+T_boolean; + table[(T_int<<4)+T_float] = (Int2Float<<12)+(Float2Float<<4)+T_boolean; + // table[(T_int<<4)+T_boolean] = T_undefined; + table[(T_int<<4)+T_char] = (Int2Int<<12)+(Char2Int<<4)+T_boolean; + table[(T_int<<4)+T_int] = (Int2Int<<12)+(Int2Int<<4)+T_boolean; + // table[(T_int<<4)+T_null] = T_undefined; + + // table[(T_null<<4)+T_undefined] = T_undefined; + // table[(T_null<<4)+T_byte] = T_undefined; + // table[(T_null<<4)+T_long] = T_undefined; + // table[(T_null<<4)+T_short] = T_undefined; + // table[(T_null<<4)+T_void] = T_undefined; + table[(T_null<<4)+T_String] = /*null2Object String2Object*/ + (T_Object<<16)+(T_null<<12)+(T_Object<<8)+(T_String<<4)+T_boolean; + table[(T_null<<4)+T_Object] = /*null2Object Object2Object*/ + (T_Object<<16)+(T_null<<12)+(T_Object<<8)+(T_Object<<4)+T_boolean; + // table[(T_null<<4)+T_double] = T_undefined; + // table[(T_null<<4)+T_float] = T_undefined; + // table[(T_null<<4)+T_boolean] = T_undefined; + // table[(T_null<<4)+T_char] = T_undefined; + // table[(T_null<<4)+T_int] = T_undefined; + table[(T_null<<4)+T_null] = /*null2Object null2Object*/ + (T_Object<<16)+(T_null<<12)+(T_Object<<8)+(T_null<<4)+T_boolean; + return table; + } + + public static final int[] get_GREATER(){ + + //the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 + + // int[] table = new int[16*16]; + return get_LESS(); + } + + public static final int[] get_GREATER_EQUAL(){ + + //the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 + + // int[] table = new int[16*16]; + return get_LESS(); + } + + public static final int[] get_LEFT_SHIFT(){ + + //the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 + + int[] table = new int[16*16]; + + // table[(T_undefined<<4)+T_undefined] = T_undefined; + // table[(T_undefined<<4)+T_byte] = T_undefined; + // table[(T_undefined<<4)+T_long] = T_undefined; + // table[(T_undefined<<4)+T_short] = T_undefined; + // table[(T_undefined<<4)+T_void] = T_undefined; + // table[(T_undefined<<4)+T_String] = T_undefined; + // table[(T_undefined<<4)+T_Object] = T_undefined; + // table[(T_undefined<<4)+T_double] = T_undefined; + // table[(T_undefined<<4)+T_float] = T_undefined; + // table[(T_undefined<<4)+T_boolean] = T_undefined; + // table[(T_undefined<<4)+T_char] = T_undefined; + // table[(T_undefined<<4)+T_int] = T_undefined; + // table[(T_undefined<<4)+T_null] = T_undefined; + + // table[(T_byte<<4)+T_undefined] = T_undefined; + table[(T_byte<<4)+T_byte] = (Byte2Int<<12)+(Byte2Int<<4)+T_int; + table[(T_byte<<4)+T_long] = (Byte2Int<<12)+(Long2Int<<4)+T_int; + table[(T_byte<<4)+T_short] = (Byte2Int<<12)+(Short2Int<<4)+T_int; + // table[(T_byte<<4)+T_void] = T_undefined; + // table[(T_byte<<4)+T_String] = T_undefined; + // table[(T_byte<<4)+T_Object] = T_undefined; + // table[(T_byte<<4)+T_double] = T_undefined; + // table[(T_byte<<4)+T_float] = T_undefined; + // table[(T_byte<<4)+T_boolean] = T_undefined; + table[(T_byte<<4)+T_char] = (Byte2Int<<12)+(Char2Int<<4)+T_int; + table[(T_byte<<4)+T_int] = (Byte2Int<<12)+(Int2Int<<4)+T_int; + // table[(T_byte<<4)+T_null] = T_undefined; + + // table[(T_long<<4)+T_undefined] = T_undefined; + table[(T_long<<4)+T_byte] = (Long2Long<<12)+(Byte2Int<<4)+T_long; + table[(T_long<<4)+T_long] = (Long2Long<<12)+(Long2Int<<4)+T_long; + table[(T_long<<4)+T_short] = (Long2Long<<12)+(Short2Int<<4)+T_long; + // table[(T_long<<4)+T_void] = T_undefined; + // table[(T_long<<4)+T_String] = T_undefined; + // table[(T_long<<4)+T_Object] = T_undefined; + // table[(T_long<<4)+T_double] = T_undefined; + // table[(T_long<<4)+T_float] = T_undefined; + // table[(T_long<<4)+T_boolean] = T_undefined; + table[(T_long<<4)+T_char] = (Long2Long<<12)+(Char2Int<<4)+T_long; + table[(T_long<<4)+T_int] = (Long2Long<<12)+(Int2Int<<4)+T_long; + // table[(T_long<<4)+T_null] = T_undefined; + + // table[(T_short<<4)+T_undefined] = T_undefined; + table[(T_short<<4)+T_byte] = (Short2Int<<12)+(Byte2Int<<4)+T_int; + table[(T_short<<4)+T_long] = (Short2Int<<12)+(Long2Int<<4)+T_int; + table[(T_short<<4)+T_short] = (Short2Int<<12)+(Short2Int<<4)+T_int; + // table[(T_short<<4)+T_void] = T_undefined; + // table[(T_short<<4)+T_String] = T_undefined; + // table[(T_short<<4)+T_Object] = T_undefined; + // table[(T_short<<4)+T_double] = T_undefined; + // table[(T_short<<4)+T_float] = T_undefined; + // table[(T_short<<4)+T_boolean] = T_undefined; + table[(T_short<<4)+T_char] = (Short2Int<<12)+(Char2Int<<4)+T_int; + table[(T_short<<4)+T_int] = (Short2Int<<12)+(Int2Int<<4)+T_int; + // table[(T_short<<4)+T_null] = T_undefined; + + // table[(T_void<<4)+T_undefined] = T_undefined; + // table[(T_void<<4)+T_byte] = T_undefined; + // table[(T_void<<4)+T_long] = T_undefined; + // table[(T_void<<4)+T_short] = T_undefined; + // table[(T_void<<4)+T_void] = T_undefined; + // table[(T_void<<4)+T_String] = T_undefined; + // table[(T_void<<4)+T_Object] = T_undefined; + // table[(T_void<<4)+T_double] = T_undefined; + // table[(T_void<<4)+T_float] = T_undefined; + // table[(T_void<<4)+T_boolean] = T_undefined; + // table[(T_void<<4)+T_char] = T_undefined; + // table[(T_void<<4)+T_int] = T_undefined; + // table[(T_void<<4)+T_null] = T_undefined; + + // table[(T_String<<4)+T_undefined] = T_undefined; + // table[(T_String<<4)+T_byte] = T_undefined; + // table[(T_String<<4)+T_long] = T_undefined; + // table[(T_String<<4)+T_short] = T_undefined; + // table[(T_String<<4)+T_void] = T_undefined; + // table[(T_String<<4)+T_String] = T_undefined; + // table[(T_String<<4)+T_Object] = T_undefined; + // table[(T_String<<4)+T_double] = T_undefined; + // table[(T_String<<4)+T_float] = T_undefined; + // table[(T_String<<4)+T_boolean] = T_undefined; + // table[(T_String<<4)+T_char] = T_undefined; + // table[(T_String<<4)+T_int] = T_undefined; + // table[(T_String<<4)+T_null] = T_undefined; + + // table[(T_Object<<4)+T_undefined] = T_undefined; + // table[(T_Object<<4)+T_byte] = T_undefined; + // table[(T_Object<<4)+T_long] = T_undefined; + // table[(T_Object<<4)+T_short] = T_undefined; + // table[(T_Object<<4)+T_void] = T_undefined; + // table[(T_Object<<4)+T_String] = T_undefined; + // table[(T_Object<<4)+T_Object] = T_undefined; + // table[(T_Object<<4)+T_double] = T_undefined; + // table[(T_Object<<4)+T_float] = T_undefined; + // table[(T_Object<<4)+T_boolean] = T_undefined; + // table[(T_Object<<4)+T_char] = T_undefined; + // table[(T_Object<<4)+T_int] = T_undefined; + // table[(T_Object<<4)+T_null] = T_undefined; + + // table[(T_double<<4)+T_undefined] = T_undefined; + // table[(T_double<<4)+T_byte] = T_undefined; + // table[(T_double<<4)+T_long] = T_undefined; + // table[(T_double<<4)+T_short] = T_undefined; + // table[(T_double<<4)+T_void] = T_undefined; + // table[(T_double<<4)+T_String] = T_undefined; + // table[(T_double<<4)+T_Object] = T_undefined; + // table[(T_double<<4)+T_double] = T_undefined; + // table[(T_double<<4)+T_float] = T_undefined; + // table[(T_double<<4)+T_boolean] = T_undefined; + // table[(T_double<<4)+T_char] = T_undefined; + // table[(T_double<<4)+T_int] = T_undefined; + // table[(T_double<<4)+T_null] = T_undefined; + + // table[(T_float<<4)+T_undefined] = T_undefined; + // table[(T_float<<4)+T_byte] = T_undefined; + // table[(T_float<<4)+T_long] = T_undefined; + // table[(T_float<<4)+T_short] = T_undefined; + // table[(T_float<<4)+T_void] = T_undefined; + // table[(T_float<<4)+T_String] = T_undefined; + // table[(T_float<<4)+T_Object] = T_undefined; + // table[(T_float<<4)+T_double] = T_undefined; + // table[(T_float<<4)+T_float] = T_undefined; + // table[(T_float<<4)+T_boolean] = T_undefined; + // table[(T_float<<4)+T_char] = T_undefined; + // table[(T_float<<4)+T_int] = T_undefined; + // table[(T_float<<4)+T_null] = T_undefined; + + // table[(T_boolean<<4)+T_undefined] = T_undefined; + // table[(T_boolean<<4)+T_byte] = T_undefined; + // table[(T_boolean<<4)+T_long] = T_undefined; + // table[(T_boolean<<4)+T_short] = T_undefined; + // table[(T_boolean<<4)+T_void] = T_undefined; + // table[(T_boolean<<4)+T_String] = T_undefined; + // table[(T_boolean<<4)+T_Object] = T_undefined; + // table[(T_boolean<<4)+T_double] = T_undefined; + // table[(T_boolean<<4)+T_float] = T_undefined; + // table[(T_boolean<<4)+T_boolean] = T_undefined; + // table[(T_boolean<<4)+T_char] = T_undefined; + // table[(T_boolean<<4)+T_int] = T_undefined; + // table[(T_boolean<<4)+T_null] = T_undefined; + + // table[(T_char<<4)+T_undefined] = T_undefined; + table[(T_char<<4)+T_byte] = (Char2Int<<12)+(Byte2Int<<4)+T_int; + table[(T_char<<4)+T_long] = (Char2Int<<12)+(Long2Int<<4)+T_int; + table[(T_char<<4)+T_short] = (Char2Int<<12)+(Short2Int<<4)+T_int; + // table[(T_char<<4)+T_void] = T_undefined; + // table[(T_char<<4)+T_String] = T_undefined; + // table[(T_char<<4)+T_Object] = T_undefined; + // table[(T_char<<4)+T_double] = T_undefined; + // table[(T_char<<4)+T_float] = T_undefined; + // table[(T_char<<4)+T_boolean] = T_undefined; + table[(T_char<<4)+T_char] = (Char2Int<<12)+(Char2Int<<4)+T_int; + table[(T_char<<4)+T_int] = (Char2Int<<12)+(Int2Int<<4)+T_int; + // table[(T_char<<4)+T_null] = T_undefined; + + // table[(T_int<<4)+T_undefined] = T_undefined; + table[(T_int<<4)+T_byte] = (Int2Int<<12)+(Byte2Int<<4)+T_int; + table[(T_int<<4)+T_long] = (Int2Int<<12)+(Long2Int<<4)+T_int; + table[(T_int<<4)+T_short] = (Int2Int<<12)+(Short2Int<<4)+T_int; + // table[(T_int<<4)+T_void] = T_undefined; + // table[(T_int<<4)+T_String] = T_undefined; + // table[(T_int<<4)+T_Object] = T_undefined; + // table[(T_int<<4)+T_double] = T_undefined; + // table[(T_int<<4)+T_float] = T_undefined; + // table[(T_int<<4)+T_boolean] = T_undefined; + table[(T_int<<4)+T_char] = (Int2Int<<12)+(Char2Int<<4)+T_int; + table[(T_int<<4)+T_int] = (Int2Int<<12)+(Int2Int<<4)+T_int; + // table[(T_int<<4)+T_null] = T_undefined; + + // table[(T_null<<4)+T_undefined] = T_undefined; + // table[(T_null<<4)+T_byte] = T_undefined; + // table[(T_null<<4)+T_long] = T_undefined; + // table[(T_null<<4)+T_short] = T_undefined; + // table[(T_null<<4)+T_void] = T_undefined; + // table[(T_null<<4)+T_String] = T_undefined; + // table[(T_null<<4)+T_Object] = T_undefined; + // table[(T_null<<4)+T_double] = T_undefined; + // table[(T_null<<4)+T_float] = T_undefined; + // table[(T_null<<4)+T_boolean] = T_undefined; + // table[(T_null<<4)+T_char] = T_undefined; + // table[(T_null<<4)+T_int] = T_undefined; + // table[(T_null<<4)+T_null] = T_undefined; + + return table; + } + + public static final int[] get_LESS(){ + + //the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 + + int[] table = new int[16*16]; + + // table[(T_undefined<<4)+T_undefined] = T_undefined; + // table[(T_undefined<<4)+T_byte] = T_undefined; + // table[(T_undefined<<4)+T_long] = T_undefined; + // table[(T_undefined<<4)+T_short] = T_undefined; + // table[(T_undefined<<4)+T_void] = T_undefined; + // table[(T_undefined<<4)+T_String] = T_undefined; + // table[(T_undefined<<4)+T_Object] = T_undefined; + // table[(T_undefined<<4)+T_double] = T_undefined; + // table[(T_undefined<<4)+T_float] = T_undefined; + // table[(T_undefined<<4)+T_boolean] = T_undefined; + // table[(T_undefined<<4)+T_char] = T_undefined; + // table[(T_undefined<<4)+T_int] = T_undefined; + // table[(T_undefined<<4)+T_null] = T_undefined; + + // table[(T_byte<<4)+T_undefined] = T_undefined; + table[(T_byte<<4)+T_byte] = (Byte2Int<<12)+(Byte2Int<<4)+T_boolean; + table[(T_byte<<4)+T_long] = (Byte2Long<<12)+(Long2Long<<4)+T_boolean; + table[(T_byte<<4)+T_short] = (Byte2Int<<12)+(Short2Int<<4)+T_boolean; + // table[(T_byte<<4)+T_void] = T_undefined; + // table[(T_byte<<4)+T_String] = T_undefined; + // table[(T_byte<<4)+T_Object] = T_undefined; + table[(T_byte<<4)+T_double] = (Byte2Double<<12)+(Double2Double<<4)+T_boolean; + table[(T_byte<<4)+T_float] = (Byte2Float<<12)+(Float2Float<<4)+T_boolean; + // table[(T_byte<<4)+T_boolean] = T_undefined; + table[(T_byte<<4)+T_char] = (Byte2Int<<12)+(Char2Int<<4)+T_boolean; + table[(T_byte<<4)+T_int] = (Byte2Int<<12)+(Int2Int<<4)+T_boolean; + // table[(T_byte<<4)+T_null] = T_undefined; + + // table[(T_long<<4)+T_undefined] = T_undefined; + table[(T_long<<4)+T_byte] = (Long2Long<<12)+(Byte2Long<<4)+T_boolean; + table[(T_long<<4)+T_long] = (Long2Long<<12)+(Long2Long<<4)+T_boolean; + table[(T_long<<4)+T_short] = (Long2Long<<12)+(Short2Long<<4)+T_boolean; + // table[(T_long<<4)+T_void] = T_undefined; + // table[(T_long<<4)+T_String] = T_undefined; + // table[(T_long<<4)+T_Object] = T_undefined; + table[(T_long<<4)+T_double] = (Long2Double<<12)+(Double2Double<<4)+T_boolean; + table[(T_long<<4)+T_float] = (Long2Float<<12)+(Float2Float<<4)+T_boolean; + // table[(T_long<<4)+T_boolean] = T_undefined; + table[(T_long<<4)+T_char] = (Long2Long<<12)+(Char2Long<<4)+T_boolean; + table[(T_long<<4)+T_int] = (Long2Long<<12)+(Int2Long<<4)+T_boolean; + // table[(T_long<<4)+T_null] = T_undefined; + + // table[(T_short<<4)+T_undefined] = T_undefined; + table[(T_short<<4)+T_byte] = (Short2Int<<12)+(Byte2Int<<4)+T_boolean; + table[(T_short<<4)+T_long] = (Short2Long<<12)+(Long2Long<<4)+T_boolean; + table[(T_short<<4)+T_short] = (Short2Int<<12)+(Short2Int<<4)+T_boolean; + // table[(T_short<<4)+T_void] = T_undefined; + // table[(T_short<<4)+T_String] = T_undefined; + // table[(T_short<<4)+T_Object] = T_undefined; + table[(T_short<<4)+T_double] = (Short2Double<<12)+(Double2Double<<4)+T_boolean; + table[(T_short<<4)+T_float] = (Short2Float<<12)+(Float2Float<<4)+T_boolean; + // table[(T_short<<4)+T_boolean] = T_undefined; + table[(T_short<<4)+T_char] = (Short2Int<<12)+(Char2Int<<4)+T_boolean; + table[(T_short<<4)+T_int] = (Short2Int<<12)+(Int2Int<<4)+T_boolean; + // table[(T_short<<4)+T_null] = T_undefined; + + // table[(T_void<<4)+T_undefined] = T_undefined; + // table[(T_void<<4)+T_byte] = T_undefined; + // table[(T_void<<4)+T_long] = T_undefined; + // table[(T_void<<4)+T_short] = T_undefined; + // table[(T_void<<4)+T_void] = T_undefined; + // table[(T_void<<4)+T_String] = T_undefined; + // table[(T_void<<4)+T_Object] = T_undefined; + // table[(T_void<<4)+T_double] = T_undefined; + // table[(T_void<<4)+T_float] = T_undefined; + // table[(T_void<<4)+T_boolean] = T_undefined; + // table[(T_void<<4)+T_char] = T_undefined; + // table[(T_void<<4)+T_int] = T_undefined; + // table[(T_void<<4)+T_null] = T_undefined; + + // table[(T_String<<4)+T_undefined] = T_undefined; + // table[(T_String<<4)+T_byte] = T_undefined; + // table[(T_String<<4)+T_long] = T_undefined; + // table[(T_String<<4)+T_short] = T_undefined; + // table[(T_String<<4)+T_void] = T_undefined; + // table[(T_String<<4)+T_String] = T_undefined; + // table[(T_String<<4)+T_Object] = T_undefined; + // table[(T_String<<4)+T_double] = T_undefined; + // table[(T_String<<4)+T_float] = T_undefined; + // table[(T_String<<4)+T_boolean] = T_undefined; + // table[(T_String<<4)+T_char] = T_undefined; + // table[(T_String<<4)+T_int] = T_undefined; + // table[(T_String<<4)+T_null] = T_undefined; + + // table[(T_Object<<4)+T_undefined] = T_undefined; + // table[(T_Object<<4)+T_byte] = T_undefined; + // table[(T_Object<<4)+T_long] = T_undefined; + // table[(T_Object<<4)+T_short] = T_undefined; + // table[(T_Object<<4)+T_void] = T_undefined; + // table[(T_Object<<4)+T_String] = T_undefined; + // table[(T_Object<<4)+T_Object] = T_undefined; + // table[(T_Object<<4)+T_double] = T_undefined; + // table[(T_Object<<4)+T_float] = T_undefined; + // table[(T_Object<<4)+T_boolean] = T_undefined; + // table[(T_Object<<4)+T_char] = T_undefined; + // table[(T_Object<<4)+T_int] = T_undefined; + // table[(T_Object<<4)+T_null] = T_undefined; + + // table[(T_double<<4)+T_undefined] = T_undefined; + table[(T_double<<4)+T_byte] = (Double2Double<<12)+(Byte2Double<<4)+T_boolean; + table[(T_double<<4)+T_long] = (Double2Double<<12)+(Long2Double<<4)+T_boolean; + table[(T_double<<4)+T_short] = (Double2Double<<12)+(Short2Double<<4)+T_boolean; + // table[(T_double<<4)+T_void] = T_undefined; + // table[(T_double<<4)+T_String] = T_undefined; + // table[(T_double<<4)+T_Object] = T_undefined; + table[(T_double<<4)+T_double] = (Double2Double<<12)+(Double2Double<<4)+T_boolean; + table[(T_double<<4)+T_float] = (Double2Double<<12)+(Float2Double<<4)+T_boolean; + // table[(T_double<<4)+T_boolean] = T_undefined; + table[(T_double<<4)+T_char] = (Double2Double<<12)+(Char2Double<<4)+T_boolean; + table[(T_double<<4)+T_int] = (Double2Double<<12)+(Int2Double<<4)+T_boolean; + // table[(T_double<<4)+T_null] = T_undefined; + + // table[(T_float<<4)+T_undefined] = T_undefined; + table[(T_float<<4)+T_byte] = (Float2Float<<12)+(Byte2Float<<4)+T_boolean; + table[(T_float<<4)+T_long] = (Float2Float<<12)+(Long2Float<<4)+T_boolean; + table[(T_float<<4)+T_short] = (Float2Float<<12)+(Short2Float<<4)+T_boolean; + // table[(T_float<<4)+T_void] = T_undefined; + // table[(T_float<<4)+T_String] = T_undefined; + // table[(T_float<<4)+T_Object] = T_undefined; + table[(T_float<<4)+T_double] = (Float2Double<<12)+(Double2Double<<4)+T_boolean; + table[(T_float<<4)+T_float] = (Float2Float<<12)+(Float2Float<<4)+T_boolean; + // table[(T_float<<4)+T_boolean] = T_undefined; + table[(T_float<<4)+T_char] = (Float2Float<<12)+(Char2Float<<4)+T_boolean; + table[(T_float<<4)+T_int] = (Float2Float<<12)+(Int2Float<<4)+T_boolean; + // table[(T_float<<4)+T_null] = T_undefined; + + // table[(T_boolean<<4)+T_undefined] = T_undefined; + // table[(T_boolean<<4)+T_byte] = T_undefined; + // table[(T_boolean<<4)+T_long] = T_undefined; + // table[(T_boolean<<4)+T_short] = T_undefined; + // table[(T_boolean<<4)+T_void] = T_undefined; + // table[(T_boolean<<4)+T_String] = T_undefined; + // table[(T_boolean<<4)+T_Object] = T_undefined; + // table[(T_boolean<<4)+T_double] = T_undefined; + // table[(T_boolean<<4)+T_float] = T_undefined; + // table[(T_boolean<<4)+T_boolean] = T_undefined; + // table[(T_boolean<<4)+T_char] = T_undefined; + // table[(T_boolean<<4)+T_int] = T_undefined; + // table[(T_boolean<<4)+T_null] = T_undefined; + + // table[(T_char<<4)+T_undefined] = T_undefined; + table[(T_char<<4)+T_byte] = (Char2Int<<12)+(Byte2Int<<4)+T_boolean; + table[(T_char<<4)+T_long] = (Char2Long<<12)+(Long2Long<<4)+T_boolean; + table[(T_char<<4)+T_short] = (Char2Int<<12)+(Short2Int<<4)+T_boolean; + // table[(T_char<<4)+T_void] = T_undefined; + // table[(T_char<<4)+T_String] = T_undefined; + // table[(T_char<<4)+T_Object] = T_undefined; + table[(T_char<<4)+T_double] = (Char2Double<<12)+(Double2Double<<4)+T_boolean; + table[(T_char<<4)+T_float] = (Char2Float<<12)+(Float2Float<<4)+T_boolean; + // table[(T_char<<4)+T_boolean] = T_undefined; + table[(T_char<<4)+T_char] = (Char2Int<<12)+(Char2Int<<4)+T_boolean; + table[(T_char<<4)+T_int] = (Char2Int<<12)+(Int2Int<<4)+T_boolean; + // table[(T_char<<4)+T_null] = T_undefined; + + // table[(T_int<<4)+T_undefined] = T_undefined; + table[(T_int<<4)+T_byte] = (Int2Int<<12)+(Byte2Int<<4)+T_boolean; + table[(T_int<<4)+T_long] = (Int2Long<<12)+(Long2Long<<4)+T_boolean; + table[(T_int<<4)+T_short] = (Int2Int<<12)+(Short2Int<<4)+T_boolean; + // table[(T_int<<4)+T_void] = T_undefined; + // table[(T_int<<4)+T_String] = T_undefined; + // table[(T_int<<4)+T_Object] = T_undefined; + table[(T_int<<4)+T_double] = (Int2Double<<12)+(Double2Double<<4)+T_boolean; + table[(T_int<<4)+T_float] = (Int2Float<<12)+(Float2Float<<4)+T_boolean; + // table[(T_int<<4)+T_boolean] = T_undefined; + table[(T_int<<4)+T_char] = (Int2Int<<12)+(Char2Int<<4)+T_boolean; + table[(T_int<<4)+T_int] = (Int2Int<<12)+(Int2Int<<4)+T_boolean; + // table[(T_int<<4)+T_null] = T_undefined; + + // table[(T_null<<4)+T_undefined] = T_undefined; + // table[(T_null<<4)+T_byte] = T_undefined; + // table[(T_null<<4)+T_long] = T_undefined; + // table[(T_null<<4)+T_short] = T_undefined; + // table[(T_null<<4)+T_void] = T_undefined; + // table[(T_null<<4)+T_String] = T_undefined; + // table[(T_null<<4)+T_Object] = T_undefined; + // table[(T_null<<4)+T_double] = T_undefined; + // table[(T_null<<4)+T_float] = T_undefined; + // table[(T_null<<4)+T_boolean] = T_undefined; + // table[(T_null<<4)+T_char] = T_undefined; + // table[(T_null<<4)+T_int] = T_undefined; + // table[(T_null<<4)+T_null] = T_undefined; + + return table; + } + + public static final int[] get_LESS_EQUAL(){ + + //the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 + + // int[] table = new int[16*16]; + return get_LESS(); + } + + public static final int[] get_MINUS(){ + + //the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 + + int[] table = new int[16*16]; + + table = (int[]) get_PLUS().clone(); + + // customization + table[(T_String<<4)+T_byte] = T_undefined; + table[(T_String<<4)+T_long] = T_undefined; + table[(T_String<<4)+T_short] = T_undefined; + table[(T_String<<4)+T_void] = T_undefined; + table[(T_String<<4)+T_String] = T_undefined; + table[(T_String<<4)+T_Object] = T_undefined; + table[(T_String<<4)+T_double] = T_undefined; + table[(T_String<<4)+T_float] = T_undefined; + table[(T_String<<4)+T_boolean] = T_undefined; + table[(T_String<<4)+T_char] = T_undefined; + table[(T_String<<4)+T_int] = T_undefined; + table[(T_String<<4)+T_null] = T_undefined; + + table[(T_byte<<4) +T_String] = T_undefined; + table[(T_long<<4) +T_String] = T_undefined; + table[(T_short<<4) +T_String] = T_undefined; + table[(T_void<<4) +T_String] = T_undefined; + table[(T_Object<<4) +T_String] = T_undefined; + table[(T_double<<4) +T_String] = T_undefined; + table[(T_float<<4) +T_String] = T_undefined; + table[(T_boolean<<4)+T_String] = T_undefined; + table[(T_char<<4) +T_String] = T_undefined; + table[(T_int<<4) +T_String] = T_undefined; + table[(T_null<<4) +T_String] = T_undefined; + + table[(T_null<<4) +T_null] = T_undefined; + + return table; + } + + public static final int[] get_MULTIPLY(){ + + //the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 + + // int[] table = new int[16*16]; + return get_MINUS(); + } + + public static final int[] get_OR(){ + + //the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 + + + // int[] table = new int[16*16]; + return get_AND(); + } + + public static final int[] get_OR_OR(){ + + //the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 + + // int[] table = new int[16*16]; + return get_AND_AND(); + } + + public static final int[] get_PLUS(){ + + //the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 + + int[] table = new int[16*16]; + + // table[(T_undefined<<4)+T_undefined] = T_undefined; + // table[(T_undefined<<4)+T_byte] = T_undefined; + // table[(T_undefined<<4)+T_long] = T_undefined; + // table[(T_undefined<<4)+T_short] = T_undefined; + // table[(T_undefined<<4)+T_void] = T_undefined; + // table[(T_undefined<<4)+T_String] = T_undefined; + // table[(T_undefined<<4)+T_Object] = T_undefined; + // table[(T_undefined<<4)+T_double] = T_undefined; + // table[(T_undefined<<4)+T_float] = T_undefined; + // table[(T_undefined<<4)+T_boolean] = T_undefined; + // table[(T_undefined<<4)+T_char] = T_undefined; + // table[(T_undefined<<4)+T_int] = T_undefined; + // table[(T_undefined<<4)+T_null] = T_undefined; + + // table[(T_byte<<4)+T_undefined] = T_undefined; + table[(T_byte<<4)+T_byte] = (Byte2Int<<12)+(Byte2Int<<4)+T_int; + table[(T_byte<<4)+T_long] = (Byte2Long<<12)+(Long2Long<<4)+T_long; + table[(T_byte<<4)+T_short] = (Byte2Int<<12)+(Short2Int<<4)+T_int; + // table[(T_byte<<4)+T_void] = T_undefined; + table[(T_byte<<4)+T_String] = (Byte2Byte<<12)+(String2String<<4)+T_String; + // table[(T_byte<<4)+T_Object] = T_undefined; + table[(T_byte<<4)+T_double] = (Byte2Double<<12)+(Double2Double<<4)+T_double; + table[(T_byte<<4)+T_float] = (Byte2Float<<12)+(Float2Float<<4)+T_float; + // table[(T_byte<<4)+T_boolean] = T_undefined; + table[(T_byte<<4)+T_char] = (Byte2Int<<12)+(Char2Int<<4)+T_int; + table[(T_byte<<4)+T_int] = (Byte2Int<<12)+(Int2Int<<4)+T_int; + // table[(T_byte<<4)+T_null] = T_undefined; + + // table[(T_long<<4)+T_undefined] = T_undefined; + table[(T_long<<4)+T_byte] = (Long2Long<<12)+(Byte2Long<<4)+T_long; + table[(T_long<<4)+T_long] = (Long2Long<<12)+(Long2Long<<4)+T_long; + table[(T_long<<4)+T_short] = (Long2Long<<12)+(Short2Long<<4)+T_long; + // table[(T_long<<4)+T_void] = T_undefined; + table[(T_long<<4)+T_String] = (Long2Long<<12)+(String2String<<4)+T_String; + // table[(T_long<<4)+T_Object] = T_undefined; + table[(T_long<<4)+T_double] = (Long2Double<<12)+(Double2Double<<4)+T_double; + table[(T_long<<4)+T_float] = (Long2Float<<12)+(Float2Float<<4)+T_float; + // table[(T_long<<4)+T_boolean] = T_undefined; + table[(T_long<<4)+T_char] = (Long2Long<<12)+(Char2Long<<4)+T_long; + table[(T_long<<4)+T_int] = (Long2Long<<12)+(Int2Long<<4)+T_long; + // table[(T_long<<4)+T_null] = T_undefined; + + // table[(T_short<<4)+T_undefined] = T_undefined; + table[(T_short<<4)+T_byte] = (Short2Int<<12)+(Byte2Int<<4)+T_int; + table[(T_short<<4)+T_long] = (Short2Long<<12)+(Long2Long<<4)+T_long; + table[(T_short<<4)+T_short] = (Short2Int<<12)+(Short2Int<<4)+T_int; + // table[(T_short<<4)+T_void] = T_undefined; + table[(T_short<<4)+T_String] = (Short2Short<<12)+(String2String<<4)+T_String; + // table[(T_short<<4)+T_Object] = T_undefined; + table[(T_short<<4)+T_double] = (Short2Double<<12)+(Double2Double<<4)+T_double; + table[(T_short<<4)+T_float] = (Short2Float<<12)+(Float2Float<<4)+T_float; + // table[(T_short<<4)+T_boolean] = T_undefined; + table[(T_short<<4)+T_char] = (Short2Int<<12)+(Char2Int<<4)+T_int; + table[(T_short<<4)+T_int] = (Short2Int<<12)+(Int2Int<<4)+T_int; + // table[(T_short<<4)+T_null] = T_undefined; + + // table[(T_void<<4)+T_undefined] = T_undefined; + // table[(T_void<<4)+T_byte] = T_undefined; + // table[(T_void<<4)+T_long] = T_undefined; + // table[(T_void<<4)+T_short] = T_undefined; + // table[(T_void<<4)+T_void] = T_undefined; + // table[(T_void<<4)+T_String] = T_undefined; + // table[(T_void<<4)+T_Object] = T_undefined; + // table[(T_void<<4)+T_double] = T_undefined; + // table[(T_void<<4)+T_float] = T_undefined; + // table[(T_void<<4)+T_boolean] = T_undefined; + // table[(T_void<<4)+T_char] = T_undefined; + // table[(T_void<<4)+T_int] = T_undefined; + // table[(T_void<<4)+T_null] = T_undefined; + + // table[(T_String<<4)+T_undefined] = T_undefined; + table[(T_String<<4)+T_byte] = (String2String<<12)+(Byte2Byte<<4)+T_String; + table[(T_String<<4)+T_long] = (String2String<<12)+(Long2Long<<4)+T_String; + table[(T_String<<4)+T_short] = (String2String<<12)+(Short2Short<<4)+T_String; + // table[(T_String<<4)+T_void] = T_undefined; + table[(T_String<<4)+T_String] = (String2String<<12)+(String2String<<4)+T_String; + table[(T_String<<4)+T_Object] = (String2String<<12)+(Object2Object<<4)+T_String; + table[(T_String<<4)+T_double] = (String2String<<12)+(Double2Double<<4)+T_String; + table[(T_String<<4)+T_float] = (String2String<<12)+(Float2Float<<4)+T_String; + table[(T_String<<4)+T_boolean] = (String2String<<12)+(Boolean2Boolean<<4)+T_String; + table[(T_String<<4)+T_char] = (String2String<<12)+(Char2Char<<4)+T_String; + table[(T_String<<4)+T_int] = (String2String<<12)+(Int2Int<<4)+T_String; + table[(T_String<<4)+T_null] = (String2String<<12)+(T_null<<8)+(T_null<<4)+T_String; + + // table[(T_Object<<4)+T_undefined] = T_undefined; + // table[(T_Object<<4)+T_byte] = T_undefined; + // table[(T_Object<<4)+T_long] = T_undefined; + // table[(T_Object<<4)+T_short] = T_undefined; + // table[(T_Object<<4)+T_void] = T_undefined; + table[(T_Object<<4)+T_String] = (Object2Object<<12)+(String2String<<4)+T_String; + // table[(T_Object<<4)+T_Object] = T_undefined; + // table[(T_Object<<4)+T_double] = T_undefined; + // table[(T_Object<<4)+T_float] = T_undefined; + // table[(T_Object<<4)+T_boolean] = T_undefined; + // table[(T_Object<<4)+T_char] = T_undefined; + // table[(T_Object<<4)+T_int] = T_undefined; + // table[(T_Object<<4)+T_null] = T_undefined; + + // table[(T_double<<4)+T_undefined] = T_undefined; + table[(T_double<<4)+T_byte] = (Double2Double<<12)+(Byte2Double<<4)+T_double; + table[(T_double<<4)+T_long] = (Double2Double<<12)+(Long2Double<<4)+T_double; + table[(T_double<<4)+T_short] = (Double2Double<<12)+(Short2Double<<4)+T_double; + // table[(T_double<<4)+T_void] = T_undefined; + table[(T_double<<4)+T_String] = (Double2Double<<12)+(String2String<<4)+T_String; + // table[(T_double<<4)+T_Object] = T_undefined; + table[(T_double<<4)+T_double] = (Double2Double<<12)+(Double2Double<<4)+T_double; + table[(T_double<<4)+T_float] = (Double2Double<<12)+(Float2Double<<4)+T_double; + // table[(T_double<<4)+T_boolean] = T_undefined; + table[(T_double<<4)+T_char] = (Double2Double<<12)+(Char2Double<<4)+T_double; + table[(T_double<<4)+T_int] = (Double2Double<<12)+(Int2Double<<4)+T_double; + // table[(T_double<<4)+T_null] = T_undefined; + + // table[(T_float<<4)+T_undefined] = T_undefined; + table[(T_float<<4)+T_byte] = (Float2Float<<12)+(Byte2Float<<4)+T_float; + table[(T_float<<4)+T_long] = (Float2Float<<12)+(Long2Float<<4)+T_float; + table[(T_float<<4)+T_short] = (Float2Float<<12)+(Short2Float<<4)+T_float; + // table[(T_float<<4)+T_void] = T_undefined; + table[(T_float<<4)+T_String] = (Float2Float<<12)+(String2String<<4)+T_String; + // table[(T_float<<4)+T_Object] = T_undefined; + table[(T_float<<4)+T_double] = (Float2Double<<12)+(Double2Double<<4)+T_double; + table[(T_float<<4)+T_float] = (Float2Float<<12)+(Float2Float<<4)+T_float; + // table[(T_float<<4)+T_boolean] = T_undefined; + table[(T_float<<4)+T_char] = (Float2Float<<12)+(Char2Float<<4)+T_float; + table[(T_float<<4)+T_int] = (Float2Float<<12)+(Int2Float<<4)+T_float; + // table[(T_float<<4)+T_null] = T_undefined; + + // table[(T_boolean<<4)+T_undefined] = T_undefined; + // table[(T_boolean<<4)+T_byte] = T_undefined; + // table[(T_boolean<<4)+T_long] = T_undefined; + // table[(T_boolean<<4)+T_short] = T_undefined; + // table[(T_boolean<<4)+T_void] = T_undefined; + table[(T_boolean<<4)+T_String] = (Boolean2Boolean<<12)+(String2String<<4)+T_String; + // table[(T_boolean<<4)+T_Object] = T_undefined; + // table[(T_boolean<<4)+T_double] = T_undefined; + // table[(T_boolean<<4)+T_float] = T_undefined; + // table[(T_boolean<<4)+T_boolean] = T_undefined; + // table[(T_boolean<<4)+T_char] = T_undefined; + // table[(T_boolean<<4)+T_int] = T_undefined; + // table[(T_boolean<<4)+T_null] = T_undefined; + + // table[(T_char<<4)+T_undefined] = T_undefined; + table[(T_char<<4)+T_byte] = (Char2Int<<12)+(Byte2Int<<4)+T_int; + table[(T_char<<4)+T_long] = (Char2Long<<12)+(Long2Long<<4)+T_long; + table[(T_char<<4)+T_short] = (Char2Int<<12)+(Short2Int<<4)+T_int; + // table[(T_char<<4)+T_void] = T_undefined; + table[(T_char<<4)+T_String] = (Char2Char<<12)+(String2String<<4)+T_String; + // table[(T_char<<4)+T_Object] = T_undefined; + table[(T_char<<4)+T_double] = (Char2Double<<12)+(Double2Double<<4)+T_double; + table[(T_char<<4)+T_float] = (Char2Float<<12)+(Float2Float<<4)+T_float; + // table[(T_char<<4)+T_boolean] = T_undefined; + table[(T_char<<4)+T_char] = (Char2Int<<12)+(Char2Int<<4)+T_int; + table[(T_char<<4)+T_int] = (Char2Int<<12)+(Int2Int<<4)+T_int; + // table[(T_char<<4)+T_null] = T_undefined; + + // table[(T_int<<4)+T_undefined] = T_undefined; + table[(T_int<<4)+T_byte] = (Int2Int<<12)+(Byte2Int<<4)+T_int; + table[(T_int<<4)+T_long] = (Int2Long<<12)+(Long2Long<<4)+T_long; + table[(T_int<<4)+T_short] = (Int2Int<<12)+(Short2Int<<4)+T_int; + // table[(T_int<<4)+T_void] = T_undefined; + table[(T_int<<4)+T_String] = (Int2Int<<12)+(String2String<<4)+T_String; + // table[(T_int<<4)+T_Object] = T_undefined; + table[(T_int<<4)+T_double] = (Int2Double<<12)+(Double2Double<<4)+T_double; + table[(T_int<<4)+T_float] = (Int2Float<<12)+(Float2Float<<4)+T_float; + // table[(T_int<<4)+T_boolean] = T_undefined; + table[(T_int<<4)+T_char] = (Int2Int<<12)+(Char2Int<<4)+T_int; + table[(T_int<<4)+T_int] = (Int2Int<<12)+(Int2Int<<4)+T_int; + // table[(T_int<<4)+T_null] = T_undefined; + + // table[(T_null<<4)+T_undefined] = T_undefined; + // table[(T_null<<4)+T_byte] = T_undefined; + // table[(T_null<<4)+T_long] = T_undefined; + // table[(T_null<<4)+T_short] = T_undefined; + // table[(T_null<<4)+T_void] = T_undefined; + table[(T_null<<4)+T_String] = (T_null<<16)+(T_null<<12)+(String2String<<4)+T_String; + // table[(T_null<<4)+T_Object] = T_undefined; + // table[(T_null<<4)+T_double] = T_undefined; + // table[(T_null<<4)+T_float] = T_undefined; + // table[(T_null<<4)+T_boolean] = T_undefined; + // table[(T_null<<4)+T_char] = T_undefined; + // table[(T_null<<4)+T_int] = T_undefined; + // table[(T_null<<4)+T_null] = (Null2String<<12)+(Null2String<<4)+T_String;; + + return table; + } + + public static final int[] get_REMAINDER(){ + + //the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 + + // int[] table = new int[16*16]; + return get_MINUS(); + } + + public static final int[] get_RIGHT_SHIFT(){ + + //the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 + + // int[] table = new int[16*16]; + return get_LEFT_SHIFT(); + } + + public static final int[] get_UNSIGNED_RIGHT_SHIFT(){ + + //the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 + + // int[] table = new int[16*16]; + return get_LEFT_SHIFT(); + } + + public static final int[] get_XOR(){ + + //the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 + + // int[] table = new int[16*16]; + return get_AND(); + } + + public String operatorToString() { + switch ((bits & OperatorMASK) >> OperatorSHIFT) { + case EQUAL_EQUAL : + return "=="; //$NON-NLS-1$ + case LESS_EQUAL : + return "<="; //$NON-NLS-1$ + case GREATER_EQUAL : + return ">="; //$NON-NLS-1$ + case NOT_EQUAL : + return "!="; //$NON-NLS-1$ + case LEFT_SHIFT : + return "<<"; //$NON-NLS-1$ + case RIGHT_SHIFT : + return ">>"; //$NON-NLS-1$ + case UNSIGNED_RIGHT_SHIFT : + return ">>>"; //$NON-NLS-1$ + case OR_OR : + return "||"; //$NON-NLS-1$ + case AND_AND : + return "&&"; //$NON-NLS-1$ + case PLUS : + return "+"; //$NON-NLS-1$ + case MINUS : + return "-"; //$NON-NLS-1$ + case NOT : + return "!"; //$NON-NLS-1$ + case REMAINDER : + return "%"; //$NON-NLS-1$ + case XOR : + return "^"; //$NON-NLS-1$ + case AND : + return "&"; //$NON-NLS-1$ + case MULTIPLY : + return "*"; //$NON-NLS-1$ + case OR : + return "|"; //$NON-NLS-1$ + case TWIDDLE : + return "~"; //$NON-NLS-1$ + case DIVIDE : + return "/"; //$NON-NLS-1$ + case GREATER : + return ">"; //$NON-NLS-1$ + case LESS : + return "<"; //$NON-NLS-1$ + case QUESTIONCOLON : + return "?:"; //$NON-NLS-1$ + case EQUAL : + return "="; //$NON-NLS-1$ + } + return "unknown operator"; //$NON-NLS-1$ + } + + public StringBuffer printExpression(int indent, StringBuffer output){ + + output.append('('); + return printExpressionNoParenthesis(0, output).append(')'); + } + + public abstract StringBuffer printExpressionNoParenthesis(int indent, StringBuffer output); +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/OperatorIds.java b/src/java/org/eclipse/jdt/internal/compiler/ast/OperatorIds.java new file mode 100644 index 0000000..c32c609 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/OperatorIds.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +public interface OperatorIds { + public static final int AND_AND = 0; + public static final int OR_OR = 1; + public static final int AND = 2; + public static final int OR = 3; + public static final int LESS = 4; + public static final int LESS_EQUAL = 5; + public static final int GREATER = 6; + public static final int GREATER_EQUAL = 7; + public static final int XOR = 8; + public static final int DIVIDE = 9; + public static final int LEFT_SHIFT = 10; + public static final int NOT = 11; + public static final int TWIDDLE = 12; + public static final int MINUS = 13; + public static final int PLUS = 14; + public static final int MULTIPLY = 15; + public static final int REMAINDER = 16; + public static final int RIGHT_SHIFT = 17; + public static final int EQUAL_EQUAL = 18; + public static final int UNSIGNED_RIGHT_SHIFT= 19; + public static final int NumberOfTables = 20; + + public static final int QUESTIONCOLON = 23; + + public static final int NOT_EQUAL = 29; + public static final int EQUAL = 30; + public static final int INSTANCEOF = 31; + public static final int PLUS_PLUS = 32; + public static final int MINUS_MINUS = 33; +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/PostfixExpression.java b/src/java/org/eclipse/jdt/internal/compiler/ast/PostfixExpression.java new file mode 100644 index 0000000..67f7b4a --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/PostfixExpression.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class PostfixExpression extends CompoundAssignment { + + public PostfixExpression(Expression l, Expression e, int op, int pos) { + + super(l, e, op, pos); + this.sourceStart = l.sourceStart; + this.sourceEnd = pos; + } + + /** + * Code generation for PostfixExpression + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ + public void generateCode( + BlockScope currentScope, + CodeStream codeStream, + boolean valueRequired) { + + // various scenarii are possible, setting an array reference, + // a field reference, a blank final field reference, a field of an enclosing instance or + // just a local variable. + + int pc = codeStream.position; + ((Reference) lhs).generatePostIncrement(currentScope, codeStream, this, valueRequired); + if (valueRequired) { + codeStream.generateImplicitConversion(implicitConversion); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public String operatorToString() { + switch (operator) { + case PLUS : + return "++"; //$NON-NLS-1$ + case MINUS : + return "--"; //$NON-NLS-1$ + } + return "unknown operator"; //$NON-NLS-1$ + } + + public StringBuffer printExpressionNoParenthesis(int indent, StringBuffer output) { + + return lhs.printExpression(indent, output).append(' ').append(operatorToString()); + } + + public boolean restrainUsageToNumericTypes() { + + return true; + } + + public void traverse(ASTVisitor visitor, BlockScope scope) { + + if (visitor.visit(this, scope)) { + lhs.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/PrefixExpression.java b/src/java/org/eclipse/jdt/internal/compiler/ast/PrefixExpression.java new file mode 100644 index 0000000..1bdb104 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/PrefixExpression.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class PrefixExpression extends CompoundAssignment { + + /** + * PrefixExpression constructor comment. + * @param l org.eclipse.jdt.internal.compiler.ast.Expression + * @param e org.eclipse.jdt.internal.compiler.ast.Expression + * @param op int + */ + public PrefixExpression(Expression l, Expression e, int op, int pos) { + + super(l, e, op, l.sourceEnd); + this.sourceStart = pos; + this.sourceEnd = l.sourceEnd; + } + + public String operatorToString() { + + switch (operator) { + case PLUS : + return "++"; //$NON-NLS-1$ + case MINUS : + return "--"; //$NON-NLS-1$ + } + return "unknown operator"; //$NON-NLS-1$ + } + + public StringBuffer printExpressionNoParenthesis(int indent, StringBuffer output) { + + output.append(operatorToString()).append(' '); + return lhs.printExpression(0, output); + } + + public boolean restrainUsageToNumericTypes() { + + return true; + } + + public void traverse(ASTVisitor visitor, BlockScope scope) { + + if (visitor.visit(this, scope)) { + lhs.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java b/src/java/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java new file mode 100644 index 0000000..af7dd02 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java @@ -0,0 +1,347 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +/** + * Variation on allocation, where can be specified an enclosing instance and an anonymous type + */ +public class QualifiedAllocationExpression extends AllocationExpression { + + //qualification may be on both side + public Expression enclosingInstance; + public TypeDeclaration anonymousType; + public ReferenceBinding superTypeBinding; + + public QualifiedAllocationExpression() { + // for subtypes + } + + public QualifiedAllocationExpression(TypeDeclaration anonymousType) { + this.anonymousType = anonymousType; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + // analyse the enclosing instance + if (enclosingInstance != null) { + flowInfo = enclosingInstance.analyseCode(currentScope, flowContext, flowInfo); + } + + // check captured variables are initialized in current context (26134) + checkCapturedLocalInitializationIfNecessary( + this.superTypeBinding == null ? this.binding.declaringClass : this.superTypeBinding, + currentScope, + flowInfo); + + // process arguments + if (arguments != null) { + for (int i = 0, count = arguments.length; i < count; i++) { + flowInfo = arguments[i].analyseCode(currentScope, flowContext, flowInfo); + } + } + + // analyse the anonymous nested type + if (anonymousType != null) { + flowInfo = anonymousType.analyseCode(currentScope, flowContext, flowInfo); + } + + // record some dependency information for exception types + ReferenceBinding[] thrownExceptions; + if (((thrownExceptions = binding.thrownExceptions).length) != 0) { + // check exception handling + flowContext.checkExceptionHandlers( + thrownExceptions, + this, + flowInfo, + currentScope); + } + manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo); + manageSyntheticAccessIfNecessary(currentScope, flowInfo); + return flowInfo; + } + + public Expression enclosingInstance() { + + return enclosingInstance; + } + + public void generateCode( + BlockScope currentScope, + CodeStream codeStream, + boolean valueRequired) { + + int pc = codeStream.position; + ReferenceBinding allocatedType = binding.declaringClass; + codeStream.new_(allocatedType); + if (valueRequired) { + codeStream.dup(); + } + // better highlight for allocation: display the type individually + codeStream.recordPositionsFrom(pc, type.sourceStart); + + // handling innerclass instance allocation - enclosing instance arguments + if (allocatedType.isNestedType()) { + codeStream.generateSyntheticEnclosingInstanceValues( + currentScope, + allocatedType, + enclosingInstance(), + this); + } + // generate the arguments for constructor + if (arguments != null) { + for (int i = 0, count = arguments.length; i < count; i++) { + arguments[i].generateCode(currentScope, codeStream, true); + } + } + // handling innerclass instance allocation - outer local arguments + if (allocatedType.isNestedType()) { + codeStream.generateSyntheticOuterArgumentValues( + currentScope, + allocatedType, + this); + } + + // invoke constructor + if (syntheticAccessor == null) { + codeStream.invokespecial(binding); + } else { + // synthetic accessor got some extra arguments appended to its signature, which need values + for (int i = 0, + max = syntheticAccessor.parameters.length - binding.parameters.length; + i < max; + i++) { + codeStream.aconst_null(); + } + codeStream.invokespecial(syntheticAccessor); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + + if (anonymousType != null) { + anonymousType.generateCode(currentScope, codeStream); + } + } + + public boolean isSuperAccess() { + + // necessary to lookup super constructor of anonymous type + return anonymousType != null; + } + + /* Inner emulation consists in either recording a dependency + * link only, or performing one level of propagation. + * + * Dependency mechanism is used whenever dealing with source target + * types, since by the time we reach them, we might not yet know their + * exact need. + */ + public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) { + + if (!flowInfo.isReachable()) return; + ReferenceBinding allocatedType; + + // perform some emulation work in case there is some and we are inside a local type only + if ((allocatedType = binding.declaringClass).isNestedType() + && currentScope.enclosingSourceType().isLocalType()) { + + if (allocatedType.isLocalType()) { + ((LocalTypeBinding) allocatedType).addInnerEmulationDependent(currentScope, enclosingInstance != null); + } else { + // locally propagate, since we already now the desired shape for sure + currentScope.propagateInnerEmulation(allocatedType, enclosingInstance != null); + } + } + } + + public StringBuffer printExpression(int indent, StringBuffer output) { + + if (enclosingInstance != null) + enclosingInstance.printExpression(0, output).append('.'); + super.printExpression(0, output); + if (anonymousType != null) { + anonymousType.print(indent, output); + } + return output; + } + + public TypeBinding resolveType(BlockScope scope) { + + // added for code assist...cannot occur with 'normal' code + if (anonymousType == null && enclosingInstance == null) { + return super.resolveType(scope); + } + + // Propagate the type checking to the arguments, and checks if the constructor is defined. + // ClassInstanceCreationExpression ::= Primary '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt + // ClassInstanceCreationExpression ::= Name '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt + // ==> by construction, when there is an enclosing instance the typename may NOT be qualified + // ==> therefore by construction the type is always a SingleTypeReferenceType instead of being either + // sometime a SingleTypeReference and sometime a QualifedTypeReference + + constant = NotAConstant; + TypeBinding enclosingInstanceType = null; + TypeBinding receiverType = null; + boolean hasError = false; + boolean enclosingInstanceContainsCast = false; + boolean argsContainCast = false; + + if (enclosingInstance != null) { + if (enclosingInstance instanceof CastExpression) { + enclosingInstance.bits |= IgnoreNeedForCastCheckMASK; // will check later on + enclosingInstanceContainsCast = true; + } + if ((enclosingInstanceType = enclosingInstance.resolveType(scope)) == null){ + hasError = true; + } else if (enclosingInstanceType.isBaseType() || enclosingInstanceType.isArrayType()) { + scope.problemReporter().illegalPrimitiveOrArrayTypeForEnclosingInstance( + enclosingInstanceType, + enclosingInstance); + hasError = true; + } else { + receiverType = ((SingleTypeReference) type).resolveTypeEnclosing(scope, (ReferenceBinding) enclosingInstanceType); + if (receiverType != null && enclosingInstanceContainsCast) { + CastExpression.checkNeedForEnclosingInstanceCast(scope, enclosingInstance, enclosingInstanceType, receiverType); + } + } + } else { + receiverType = type.resolveType(scope); + } + if (receiverType == null) { + hasError = true; + } else if (((ReferenceBinding) receiverType).isFinal() && this.anonymousType != null) { + scope.problemReporter().anonymousClassCannotExtendFinalClass(type, receiverType); + hasError = true; + } + + // will check for null after args are resolved + TypeBinding[] argumentTypes = NoParameters; + if (arguments != null) { + int length = arguments.length; + argumentTypes = new TypeBinding[length]; + for (int i = 0; i < length; i++) { + Expression argument = this.arguments[i]; + if (argument instanceof CastExpression) { + argument.bits |= IgnoreNeedForCastCheckMASK; // will check later on + argsContainCast = true; + } + if ((argumentTypes[i] = argument.resolveType(scope)) == null){ + hasError = true; + } + } + } + // limit of fault-tolerance + if (hasError) return this.resolvedType = receiverType; + + if (this.anonymousType == null) { + // qualified allocation with no anonymous type + ReferenceBinding allocationType = (ReferenceBinding) receiverType; + if (!receiverType.canBeInstantiated()) { + scope.problemReporter().cannotInstantiate(type, receiverType); + return this.resolvedType = receiverType; + } + if ((this.binding = scope.getConstructor(allocationType, argumentTypes, this)).isValidBinding()) { + if (isMethodUseDeprecated(binding, scope)) { + scope.problemReporter().deprecatedMethod(this.binding, this); + } + if (arguments != null) { + for (int i = 0; i < arguments.length; i++) { + arguments[i].implicitWidening(this.binding.parameters[i], argumentTypes[i]); + } + if (argsContainCast) { + CastExpression.checkNeedForArgumentCasts(scope, null, allocationType, binding, this.arguments, argumentTypes, this); + } + } + } else { + if (this.binding.declaringClass == null) { + this.binding.declaringClass = allocationType; + } + scope.problemReporter().invalidConstructor(this, this.binding); + return this.resolvedType = receiverType; + } + + // The enclosing instance must be compatible with the innermost enclosing type + ReferenceBinding expectedType = this.binding.declaringClass.enclosingType(); + if (enclosingInstanceType.isCompatibleWith(expectedType)) { + return receiverType; + } + scope.problemReporter().typeMismatchErrorActualTypeExpectedType( + this.enclosingInstance, + enclosingInstanceType, + expectedType); + return this.resolvedType = receiverType; + } + + // anonymous type scenario + // an anonymous class inherits from java.lang.Object when declared "after" an interface + this.superTypeBinding = receiverType.isInterface() ? scope.getJavaLangObject() : (ReferenceBinding) receiverType; + // insert anonymous type in scope + scope.addAnonymousType(this.anonymousType, (ReferenceBinding) receiverType); + this.anonymousType.resolve(scope); + + // find anonymous super constructor + MethodBinding inheritedBinding = scope.getConstructor(this.superTypeBinding, argumentTypes, this); + if (!inheritedBinding.isValidBinding()) { + if (inheritedBinding.declaringClass == null) { + inheritedBinding.declaringClass = this.superTypeBinding; + } + scope.problemReporter().invalidConstructor(this, inheritedBinding); + return this.resolvedType = anonymousType.binding; + } + if (enclosingInstance != null) { + ReferenceBinding targetEnclosing = inheritedBinding.declaringClass.enclosingType(); + if (targetEnclosing == null) { + scope.problemReporter().unnecessaryEnclosingInstanceSpecification(enclosingInstance, (ReferenceBinding)receiverType); + return this.resolvedType = anonymousType.binding; + } else if (!enclosingInstanceType.isCompatibleWith(targetEnclosing)) { + scope.problemReporter().typeMismatchErrorActualTypeExpectedType(enclosingInstance, enclosingInstanceType, targetEnclosing); + return this.resolvedType = anonymousType.binding; + } + } + + // this promotion has to be done somewhere: here or inside the constructor of the + // anonymous class. We do it here while the constructor of the inner is then easier. + if (arguments != null) { + for (int i = 0; i < arguments.length; i++) { + arguments[i].implicitWidening(inheritedBinding.parameters[i], argumentTypes[i]); + } + if (argsContainCast) { + CastExpression.checkNeedForArgumentCasts(scope, null, this.superTypeBinding, inheritedBinding, this.arguments, argumentTypes, this); + } + } + // Update the anonymous inner class : superclass, interface + binding = anonymousType.createsInternalConstructorWithBinding(inheritedBinding); + return this.resolvedType = anonymousType.binding; // 1.2 change + } + + public void traverse(ASTVisitor visitor, BlockScope scope) { + + if (visitor.visit(this, scope)) { + if (enclosingInstance != null) + enclosingInstance.traverse(visitor, scope); + type.traverse(visitor, scope); + if (arguments != null) { + int argumentsLength = arguments.length; + for (int i = 0; i < argumentsLength; i++) + arguments[i].traverse(visitor, scope); + } + if (anonymousType != null) + anonymousType.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java b/src/java/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java new file mode 100644 index 0000000..8afa15a --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java @@ -0,0 +1,812 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; +import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; + +public class QualifiedNameReference extends NameReference { + + public char[][] tokens; + public long[] sourcePositions; + public FieldBinding[] otherBindings, otherCodegenBindings; + int[] otherDepths; + public int indexOfFirstFieldBinding;//points (into tokens) for the first token that corresponds to first FieldBinding + SyntheticAccessMethodBinding syntheticWriteAccessor; + SyntheticAccessMethodBinding[] syntheticReadAccessors; + protected FieldBinding lastFieldBinding; + public QualifiedNameReference( + char[][] sources, + long[] positions, + int sourceStart, + int sourceEnd) { + super(); + this.tokens = sources; + this.sourcePositions = positions; + this.sourceStart = sourceStart; + this.sourceEnd = sourceEnd; + } + public FlowInfo analyseAssignment( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo, + Assignment assignment, + boolean isCompound) { + + // determine the rank until which we now we do not need any actual value for the field access + int otherBindingsCount = otherBindings == null ? 0 : otherBindings.length; + boolean needValue = otherBindingsCount == 0 || !this.otherBindings[0].isStatic(); + switch (bits & RestrictiveFlagMASK) { + case FIELD : // reading a field + lastFieldBinding = (FieldBinding) binding; + if (needValue) { + manageSyntheticReadAccessIfNecessary(currentScope, lastFieldBinding, this.actualReceiverType, 0, flowInfo); + } // check if final blank field + if (lastFieldBinding.isBlankFinal() + && this.otherBindings != null // the last field binding is only assigned + && currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)) { + if (!flowInfo.isDefinitelyAssigned(lastFieldBinding)) { + currentScope.problemReporter().uninitializedBlankFinalField( + lastFieldBinding, + this); + } + } + break; + case LOCAL : + // first binding is a local variable + LocalVariableBinding localBinding; + if (!flowInfo + .isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) { + currentScope.problemReporter().uninitializedLocalVariable(localBinding, this); + } + if (flowInfo.isReachable()) { + localBinding.useFlag = LocalVariableBinding.USED; + } else if (localBinding.useFlag == LocalVariableBinding.UNUSED) { + localBinding.useFlag = LocalVariableBinding.FAKE_USED; + } + } + + if (needValue) { + manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo); + // only for first binding + } + // all intermediate field accesses are read accesses + if (otherBindings != null) { + for (int i = 0; i < otherBindingsCount-1; i++) { + lastFieldBinding = otherBindings[i]; + needValue = !otherBindings[i+1].isStatic(); + if (needValue) { + manageSyntheticReadAccessIfNecessary( + currentScope, + lastFieldBinding, + i == 0 + ? ((VariableBinding)binding).type + : otherBindings[i-1].type, + i + 1, + flowInfo); + } + } + lastFieldBinding = otherBindings[otherBindingsCount-1]; + } + + if (isCompound) { + if (binding == lastFieldBinding + && lastFieldBinding.isBlankFinal() + && currentScope.allowBlankFinalFieldAssignment(lastFieldBinding) + && (!flowInfo.isDefinitelyAssigned(lastFieldBinding))) { + currentScope.problemReporter().uninitializedBlankFinalField( + lastFieldBinding, + this); + } + TypeBinding lastReceiverType; + if (lastFieldBinding == binding){ + lastReceiverType = this.actualReceiverType; + } else if (otherBindingsCount == 1){ + lastReceiverType = ((VariableBinding)this.binding).type; + } else { + lastReceiverType = this.otherBindings[otherBindingsCount-2].type; + } + manageSyntheticReadAccessIfNecessary( + currentScope, + lastFieldBinding, + lastReceiverType, + lastFieldBinding == binding + ? 0 + : otherBindingsCount, + flowInfo); + } + + if (assignment.expression != null) { + flowInfo = + assignment + .expression + .analyseCode(currentScope, flowContext, flowInfo) + .unconditionalInits(); + } + + // the last field access is a write access + if (lastFieldBinding.isFinal()) { + // in a context where it can be assigned? + if (lastFieldBinding.isBlankFinal() + && !isCompound + && currentScope.allowBlankFinalFieldAssignment(lastFieldBinding) + && indexOfFirstFieldBinding == 1) { + if (flowInfo.isPotentiallyAssigned(lastFieldBinding)) { + currentScope.problemReporter().duplicateInitializationOfBlankFinalField(lastFieldBinding, this); + } else { + flowContext.recordSettingFinal(lastFieldBinding, this, flowInfo); + } + flowInfo.markAsDefinitelyAssigned(lastFieldBinding); + } else { + currentScope.problemReporter().cannotAssignToFinalField(lastFieldBinding, this); + if (currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)) { // pretend it got assigned + flowInfo.markAsDefinitelyAssigned(lastFieldBinding); + } + } + } + // equivalent to valuesRequired[maxOtherBindings] + TypeBinding lastReceiverType; + if (lastFieldBinding == binding){ + lastReceiverType = this.actualReceiverType; + } else if (otherBindingsCount == 1){ + lastReceiverType = ((VariableBinding)this.binding).type; + } else { + lastReceiverType = this.otherBindings[otherBindingsCount-2].type; + } + manageSyntheticWriteAccessIfNecessary(currentScope, lastFieldBinding, lastReceiverType, flowInfo); + + return flowInfo; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + return analyseCode(currentScope, flowContext, flowInfo, true); + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo, + boolean valueRequired) { + + // determine the rank until which we now we do not need any actual value for the field access + int otherBindingsCount = otherBindings == null ? 0 : otherBindings.length; + + boolean needValue = otherBindingsCount == 0 ? valueRequired : !this.otherBindings[0].isStatic(); + switch (bits & RestrictiveFlagMASK) { + case FIELD : // reading a field + if (needValue) { + manageSyntheticReadAccessIfNecessary(currentScope, (FieldBinding) binding, this.actualReceiverType, 0, flowInfo); + } + // check if reading a final blank field + FieldBinding fieldBinding; + if ((fieldBinding = (FieldBinding) binding).isBlankFinal() + && (indexOfFirstFieldBinding == 1) + // was an implicit reference to the first field binding + && currentScope.allowBlankFinalFieldAssignment(fieldBinding) + && (!flowInfo.isDefinitelyAssigned(fieldBinding))) { + currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this); + } + break; + case LOCAL : // reading a local variable + LocalVariableBinding localBinding; + if (!flowInfo + .isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) { + currentScope.problemReporter().uninitializedLocalVariable(localBinding, this); + } + if (flowInfo.isReachable()) { + localBinding.useFlag = LocalVariableBinding.USED; + } else if (localBinding.useFlag == LocalVariableBinding.UNUSED) { + localBinding.useFlag = LocalVariableBinding.FAKE_USED; + } + } + if (needValue) { + manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo); + // only for first binding + } + if (otherBindings != null) { + for (int i = 0; i < otherBindingsCount; i++) { + needValue = i < otherBindingsCount-1 ? !otherBindings[i+1].isStatic() : valueRequired; + if (needValue) { + manageSyntheticReadAccessIfNecessary( + currentScope, + otherBindings[i], + i == 0 + ? ((VariableBinding)binding).type + : otherBindings[i-1].type, + i + 1, + flowInfo); + } + } + } + return flowInfo; + } + /** + * Check and/or redirect the field access to the delegate receiver if any + */ + public TypeBinding checkFieldAccess(BlockScope scope) { + // check for forward references + FieldBinding fieldBinding = (FieldBinding) binding; + MethodScope methodScope = scope.methodScope(); + if (methodScope.enclosingSourceType() == fieldBinding.declaringClass + && methodScope.lastVisibleFieldID >= 0 + && fieldBinding.id >= methodScope.lastVisibleFieldID) { + if ((!fieldBinding.isStatic() || methodScope.isStatic) + && this.indexOfFirstFieldBinding == 1) + scope.problemReporter().forwardReference(this, 0, scope.enclosingSourceType()); + } + bits &= ~RestrictiveFlagMASK; // clear bits + bits |= FIELD; + return getOtherFieldBindings(scope); + } + public void generateAssignment( + BlockScope currentScope, + CodeStream codeStream, + Assignment assignment, + boolean valueRequired) { + + generateReadSequence(currentScope, codeStream); + assignment.expression.generateCode(currentScope, codeStream, true); + fieldStore(codeStream, lastFieldBinding, syntheticWriteAccessor, valueRequired); + // equivalent to valuesRequired[maxOtherBindings] + if (valueRequired) { + codeStream.generateImplicitConversion(assignment.implicitConversion); + } + } + public void generateCode( + BlockScope currentScope, + CodeStream codeStream, + boolean valueRequired) { + + int pc = codeStream.position; + if (constant != NotAConstant) { + if (valueRequired) { + codeStream.generateConstant(constant, implicitConversion); + } + } else { + generateReadSequence(currentScope, codeStream); + if (valueRequired) { + if (lastFieldBinding.declaringClass == null) { // array length + codeStream.arraylength(); + codeStream.generateImplicitConversion(implicitConversion); + } else { + if (lastFieldBinding.constant != NotAConstant) { + if (!lastFieldBinding.isStatic()){ + codeStream.invokeObjectGetClass(); + codeStream.pop(); + } + // inline the last field constant + codeStream.generateConstant(lastFieldBinding.constant, implicitConversion); + } else { + SyntheticAccessMethodBinding accessor = + syntheticReadAccessors == null + ? null + : syntheticReadAccessors[syntheticReadAccessors.length - 1]; + if (accessor == null) { + if (lastFieldBinding.isStatic()) { + codeStream.getstatic(lastFieldBinding); + } else { + codeStream.getfield(lastFieldBinding); + } + } else { + codeStream.invokestatic(accessor); + } + codeStream.generateImplicitConversion(implicitConversion); + } + } + } else { + if (lastFieldBinding != null && !lastFieldBinding.isStatic()){ + codeStream.invokeObjectGetClass(); // perform null check + codeStream.pop(); + } + + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + public void generateCompoundAssignment( + BlockScope currentScope, + CodeStream codeStream, + Expression expression, + int operator, + int assignmentImplicitConversion, + boolean valueRequired) { + + generateReadSequence(currentScope, codeStream); + SyntheticAccessMethodBinding accessor = + syntheticReadAccessors == null + ? null + : syntheticReadAccessors[syntheticReadAccessors.length - 1]; + if (lastFieldBinding.isStatic()) { + if (accessor == null) { + codeStream.getstatic(lastFieldBinding); + } else { + codeStream.invokestatic(accessor); + } + } else { + codeStream.dup(); + if (accessor == null) { + codeStream.getfield(lastFieldBinding); + } else { + codeStream.invokestatic(accessor); + } + } + // the last field access is a write access + // perform the actual compound operation + int operationTypeID; + if ((operationTypeID = implicitConversion >> 4) == T_String) { + codeStream.generateStringAppend(currentScope, null, expression); + } else { + // promote the array reference to the suitable operation type + codeStream.generateImplicitConversion(implicitConversion); + // generate the increment value (will by itself be promoted to the operation value) + if (expression == IntLiteral.One) { // prefix operation + codeStream.generateConstant(expression.constant, implicitConversion); + } else { + expression.generateCode(currentScope, codeStream, true); + } + // perform the operation + codeStream.sendOperator(operator, operationTypeID); + // cast the value back to the array reference type + codeStream.generateImplicitConversion(assignmentImplicitConversion); + } + // actual assignment + fieldStore(codeStream, lastFieldBinding, syntheticWriteAccessor, valueRequired); + // equivalent to valuesRequired[maxOtherBindings] + } + public void generatePostIncrement( + BlockScope currentScope, + CodeStream codeStream, + CompoundAssignment postIncrement, + boolean valueRequired) { + generateReadSequence(currentScope, codeStream); + SyntheticAccessMethodBinding accessor = + syntheticReadAccessors == null + ? null + : syntheticReadAccessors[syntheticReadAccessors.length - 1]; + if (lastFieldBinding.isStatic()) { + if (accessor == null) { + codeStream.getstatic(lastFieldBinding); + } else { + codeStream.invokestatic(accessor); + } + } else { + codeStream.dup(); + if (accessor == null) { + codeStream.getfield(lastFieldBinding); + } else { + codeStream.invokestatic(accessor); + } + } + // duplicate the old field value + if (valueRequired) { + if (lastFieldBinding.isStatic()) { + if ((lastFieldBinding.type == LongBinding) + || (lastFieldBinding.type == DoubleBinding)) { + codeStream.dup2(); + } else { + codeStream.dup(); + } + } else { // Stack: [owner][old field value] ---> [old field value][owner][old field value] + if ((lastFieldBinding.type == LongBinding) + || (lastFieldBinding.type == DoubleBinding)) { + codeStream.dup2_x1(); + } else { + codeStream.dup_x1(); + } + } + } + codeStream.generateConstant( + postIncrement.expression.constant, + implicitConversion); + codeStream.sendOperator(postIncrement.operator, lastFieldBinding.type.id); + codeStream.generateImplicitConversion( + postIncrement.assignmentImplicitConversion); + fieldStore(codeStream, lastFieldBinding, syntheticWriteAccessor, false); + } + /* + * Generate code for all bindings (local and fields) excluding the last one, which may then be generated code + * for a read or write access. + */ + public void generateReadSequence( + BlockScope currentScope, + CodeStream codeStream) { + + // determine the rank until which we now we do not need any actual value for the field access + int otherBindingsCount = this.otherCodegenBindings == null ? 0 : otherCodegenBindings.length; + + boolean needValue = otherBindingsCount == 0 || !this.otherBindings[0].isStatic(); + switch (bits & RestrictiveFlagMASK) { + case FIELD : + lastFieldBinding = (FieldBinding) this.codegenBinding; + // if first field is actually constant, we can inline it + if (lastFieldBinding.constant != NotAConstant) { + break; + } + if (needValue && !lastFieldBinding.isStatic()) { + if ((bits & DepthMASK) != 0) { + ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT); + Object[] emulationPath = currentScope.getEmulationPath(targetType, true /*only exact match*/, false/*consider enclosing arg*/); + codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope); + } else { + generateReceiver(codeStream); + } + } + break; + case LOCAL : // reading the first local variable + lastFieldBinding = null; + if (!needValue) break; // no value needed + LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding; + // regular local variable read + if (localBinding.constant != NotAConstant) { + codeStream.generateConstant(localBinding.constant, 0); + // no implicit conversion + } else { + // outer local? + if ((bits & DepthMASK) != 0) { + // outer local can be reached either through a synthetic arg or a synthetic field + VariableBinding[] path = currentScope.getEmulationPath(localBinding); + codeStream.generateOuterAccess(path, this, localBinding, currentScope); + } else { + codeStream.load(localBinding); + } + } + } + + // all intermediate field accesses are read accesses + // only the last field binding is a write access + if (this.otherCodegenBindings != null) { + for (int i = 0; i < otherBindingsCount; i++) { + FieldBinding nextField = this.otherCodegenBindings[i]; + if (lastFieldBinding != null) { + needValue = !nextField.isStatic(); + if (needValue) { + MethodBinding accessor = + syntheticReadAccessors == null ? null : syntheticReadAccessors[i]; + if (accessor == null) { + if (lastFieldBinding.constant != NotAConstant) { + if (this.lastFieldBinding != this.codegenBinding && !this.lastFieldBinding.isStatic()) { + codeStream.invokeObjectGetClass(); // perform null check + codeStream.pop(); + } + codeStream.generateConstant(lastFieldBinding.constant, 0); + } else if (lastFieldBinding.isStatic()) { + codeStream.getstatic(lastFieldBinding); + } else { + codeStream.getfield(lastFieldBinding); + } + } else { + codeStream.invokestatic(accessor); + } + } else { + if (this.codegenBinding != this.lastFieldBinding && !this.lastFieldBinding.isStatic()){ + codeStream.invokeObjectGetClass(); // perform null check + codeStream.pop(); + } + } + } + this.lastFieldBinding = nextField; + } + } + } + public void generateReceiver(CodeStream codeStream) { + codeStream.aload_0(); + } + public TypeBinding getOtherFieldBindings(BlockScope scope) { + // At this point restrictiveFlag may ONLY have two potential value : FIELD LOCAL (i.e cast <<(VariableBinding) binding>> is valid) + int length = tokens.length; + if ((bits & FIELD) != 0) { + FieldBinding fieldBinding = (FieldBinding) binding; + if (!fieldBinding.isStatic()) { + //must check for the static status.... + if (indexOfFirstFieldBinding > 1 //accessing to a field using a type as "receiver" is allowed only with static field + || scope.methodScope().isStatic) { // the field is the first token of the qualified reference.... + scope.problemReporter().staticFieldAccessToNonStaticVariable(this, fieldBinding); + return null; + } + } else { + // indirect static reference ? + if (indexOfFirstFieldBinding > 1 + && fieldBinding.declaringClass != actualReceiverType) { + scope.problemReporter().indirectAccessToStaticField(this, fieldBinding); + } + } + // only last field is actually a write access if any + if (isFieldUseDeprecated(fieldBinding, scope, (this.bits & IsStrictlyAssignedMASK) !=0 && indexOfFirstFieldBinding == length)) + scope.problemReporter().deprecatedField(fieldBinding, this); + } + TypeBinding type = ((VariableBinding) binding).type; + int index = indexOfFirstFieldBinding; + if (index == length) { // restrictiveFlag == FIELD + this.constant = FieldReference.getConstantFor((FieldBinding) binding, this, false, scope); + return type; + } + // allocation of the fieldBindings array and its respective constants + int otherBindingsLength = length - index; + otherCodegenBindings = otherBindings = new FieldBinding[otherBindingsLength]; + otherDepths = new int[otherBindingsLength]; + + // fill the first constant (the one of the binding) + this.constant = + ((bits & FIELD) != 0) + ? FieldReference.getConstantFor((FieldBinding) binding, this, false, scope) + : ((VariableBinding) binding).constant; + // save first depth, since will be updated by visibility checks of other bindings + int firstDepth = (bits & DepthMASK) >> DepthSHIFT; + // iteration on each field + while (index < length) { + char[] token = tokens[index]; + if (type == null) + return null; // could not resolve type prior to this point + + bits &= ~DepthMASK; // flush previous depth if any + FieldBinding field = scope.getField(type, token, this); + int place = index - indexOfFirstFieldBinding; + otherBindings[place] = field; + otherDepths[place] = (bits & DepthMASK) >> DepthSHIFT; + if (field.isValidBinding()) { + // only last field is actually a write access if any + if (isFieldUseDeprecated(field, scope, (this.bits & IsStrictlyAssignedMASK) !=0 && index+1 == length)) { + scope.problemReporter().deprecatedField(field, this); + } + Constant someConstant = FieldReference.getConstantFor(field, this, false, scope); + // constant propagation can only be performed as long as the previous one is a constant too. + if (this.constant != NotAConstant) { + this.constant = someConstant; + } + + if (field.isStatic()) { + // static field accessed through receiver? legal but unoptimal (optional warning) + scope.problemReporter().nonStaticAccessToStaticField(this, field); + // indirect static reference ? + if (field.declaringClass != type) { + scope.problemReporter().indirectAccessToStaticField(this, field); + } + } + type = field.type; + index++; + } else { + constant = NotAConstant; //don't fill other constants slots... + scope.problemReporter().invalidField(this, field, index, type); + setDepth(firstDepth); + return null; + } + } + setDepth(firstDepth); + return (otherBindings[otherBindingsLength - 1]).type; + } + public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) { + if (!flowInfo.isReachable()) return; + //If inlinable field, forget the access emulation, the code gen will directly target it + if (((bits & DepthMASK) == 0) || (constant != NotAConstant)) { + return; + } + if ((bits & RestrictiveFlagMASK) == LOCAL) { + currentScope.emulateOuterAccess((LocalVariableBinding) binding); + } + } + public void manageSyntheticReadAccessIfNecessary( + BlockScope currentScope, + FieldBinding fieldBinding, + TypeBinding lastReceiverType, + int index, + FlowInfo flowInfo) { + if (!flowInfo.isReachable()) return; + // index == 0 denotes the first fieldBinding, index > 0 denotes one of the 'otherBindings' + if (fieldBinding.constant != NotAConstant) + return; + if (fieldBinding.isPrivate()) { // private access + if (fieldBinding.declaringClass != currentScope.enclosingSourceType()) { + if (syntheticReadAccessors == null) { + if (otherBindings == null) + syntheticReadAccessors = new SyntheticAccessMethodBinding[1]; + else + syntheticReadAccessors = + new SyntheticAccessMethodBinding[otherBindings.length + 1]; + } + syntheticReadAccessors[index] = ((SourceTypeBinding) fieldBinding.declaringClass).addSyntheticMethod(fieldBinding, true); + currentScope.problemReporter().needToEmulateFieldReadAccess(fieldBinding, this); + return; + } + } else if (fieldBinding.isProtected()){ + int depth = index == 0 ? (bits & DepthMASK) >> DepthSHIFT : otherDepths[index-1]; + // implicit protected access (only for first one) + if (depth > 0 && (fieldBinding.declaringClass.getPackage() + != currentScope.enclosingSourceType().getPackage())) { + if (syntheticReadAccessors == null) { + if (otherBindings == null) + syntheticReadAccessors = new SyntheticAccessMethodBinding[1]; + else + syntheticReadAccessors = + new SyntheticAccessMethodBinding[otherBindings.length + 1]; + } + syntheticReadAccessors[index] = + ((SourceTypeBinding) currentScope.enclosingSourceType().enclosingTypeAt(depth)) + .addSyntheticMethod(fieldBinding, true); + currentScope.problemReporter().needToEmulateFieldReadAccess(fieldBinding, this); + return; + } + } + // if the binding declaring class is not visible, need special action + // for runtime compatibility on 1.2 VMs : change the declaring class of the binding + // NOTE: from target 1.2 on, field's declaring class is touched if any different from receiver type + if (fieldBinding.declaringClass != lastReceiverType + && !lastReceiverType.isArrayType() + && fieldBinding.declaringClass != null + && fieldBinding.constant == NotAConstant + && ((currentScope.environment().options.targetJDK >= ClassFileConstants.JDK1_2 + && (index > 0 || indexOfFirstFieldBinding > 1 || !fieldBinding.isStatic()) + && fieldBinding.declaringClass.id != T_Object) + || !fieldBinding.declaringClass.canBeSeenBy(currentScope))){ + if (index == 0){ + this.codegenBinding = currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding, (ReferenceBinding)lastReceiverType); + } else { + if (this.otherCodegenBindings == this.otherBindings){ + int l = this.otherBindings.length; + System.arraycopy(this.otherBindings, 0, this.otherCodegenBindings = new FieldBinding[l], 0, l); + } + this.otherCodegenBindings[index-1] = currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding, (ReferenceBinding)lastReceiverType); + } + } + } + /* + * No need to emulate access to protected fields since not implicitly accessed + */ + public void manageSyntheticWriteAccessIfNecessary( + BlockScope currentScope, + FieldBinding fieldBinding, + TypeBinding lastReceiverType, + FlowInfo flowInfo) { + if (!flowInfo.isReachable()) return; + if (fieldBinding.isPrivate()) { + if (fieldBinding.declaringClass != currentScope.enclosingSourceType()) { + syntheticWriteAccessor = ((SourceTypeBinding) fieldBinding.declaringClass) + .addSyntheticMethod(fieldBinding, false); + currentScope.problemReporter().needToEmulateFieldWriteAccess(fieldBinding, this); + return; + } + } else if (fieldBinding.isProtected()){ + int depth = fieldBinding == binding ? (bits & DepthMASK) >> DepthSHIFT : otherDepths[otherDepths.length-1]; + if (depth > 0 && (fieldBinding.declaringClass.getPackage() + != currentScope.enclosingSourceType().getPackage())) { + syntheticWriteAccessor = ((SourceTypeBinding) currentScope.enclosingSourceType().enclosingTypeAt(depth)) + .addSyntheticMethod(fieldBinding, false); + currentScope.problemReporter().needToEmulateFieldWriteAccess(fieldBinding, this); + return; + } + } + // if the binding declaring class is not visible, need special action + // for runtime compatibility on 1.2 VMs : change the declaring class of the binding + // NOTE: from target 1.2 on, field's declaring class is touched if any different from receiver type + if (fieldBinding.declaringClass != lastReceiverType + && !lastReceiverType.isArrayType() + && fieldBinding.declaringClass != null + && fieldBinding.constant == NotAConstant + && ((currentScope.environment().options.targetJDK >= ClassFileConstants.JDK1_2 + && (fieldBinding != binding || indexOfFirstFieldBinding > 1 || !fieldBinding.isStatic()) + && fieldBinding.declaringClass.id != T_Object) + || !fieldBinding.declaringClass.canBeSeenBy(currentScope))){ + if (fieldBinding == binding){ + this.codegenBinding = currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding, (ReferenceBinding)lastReceiverType); + } else { + if (this.otherCodegenBindings == this.otherBindings){ + int l = this.otherBindings.length; + System.arraycopy(this.otherBindings, 0, this.otherCodegenBindings = new FieldBinding[l], 0, l); + } + this.otherCodegenBindings[this.otherCodegenBindings.length-1] = currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding, (ReferenceBinding)lastReceiverType); + } + } + + } + + public StringBuffer printExpression(int indent, StringBuffer output) { + + for (int i = 0; i < tokens.length; i++) { + if (i > 0) output.append('.'); + output.append(tokens[i]); + } + return output; + } + + /** + * Normal field binding did not work, try to bind to a field of the delegate receiver. + */ + public TypeBinding reportError(BlockScope scope) { + if (binding instanceof ProblemFieldBinding) { + scope.problemReporter().invalidField(this, (FieldBinding) binding); + } else if (binding instanceof ProblemReferenceBinding) { + scope.problemReporter().invalidType(this, (TypeBinding) binding); + } else { + scope.problemReporter().unresolvableReference(this, binding); + } + return null; + } + public TypeBinding resolveType(BlockScope scope) { + // field and/or local are done before type lookups + // the only available value for the restrictiveFlag BEFORE + // the TC is Flag_Type Flag_LocalField and Flag_TypeLocalField + this.actualReceiverType = this.receiverType = scope.enclosingSourceType(); + constant = Constant.NotAConstant; + if ((this.codegenBinding = this.binding = scope.getBinding(tokens, bits & RestrictiveFlagMASK, this, true /*resolve*/)).isValidBinding()) { + switch (bits & RestrictiveFlagMASK) { + case VARIABLE : //============only variable=========== + case TYPE | VARIABLE : + if (binding instanceof LocalVariableBinding) { + if (!((LocalVariableBinding) binding).isFinal() && ((bits & DepthMASK) != 0)) + scope.problemReporter().cannotReferToNonFinalOuterLocal( + (LocalVariableBinding) binding, + this); + bits &= ~RestrictiveFlagMASK; // clear bits + bits |= LOCAL; + return this.resolvedType = getOtherFieldBindings(scope); + } + if (binding instanceof FieldBinding) { + // check for forward references + FieldBinding fieldBinding = (FieldBinding) binding; + MethodScope methodScope = scope.methodScope(); + if (methodScope.enclosingSourceType() == fieldBinding.declaringClass + && methodScope.lastVisibleFieldID >= 0 + && fieldBinding.id >= methodScope.lastVisibleFieldID) { + if ((!fieldBinding.isStatic() || methodScope.isStatic) + && this.indexOfFirstFieldBinding == 1) { + scope.problemReporter().forwardReference(this, 0, scope.enclosingSourceType()); + } + } + if (!fieldBinding.isStatic() + && this.indexOfFirstFieldBinding == 1 + && scope.environment().options.getSeverity(CompilerOptions.UnqualifiedFieldAccess) != ProblemSeverities.Ignore) { + scope.problemReporter().unqualifiedFieldAccess(this, fieldBinding); + } + bits &= ~RestrictiveFlagMASK; // clear bits + bits |= FIELD; + + // check for deprecated receiver type + // deprecation check for receiver type if not first token + if (indexOfFirstFieldBinding > 1) { + if (isTypeUseDeprecated(this.actualReceiverType, scope)) + scope.problemReporter().deprecatedType(this.actualReceiverType, this); + } + + return this.resolvedType = getOtherFieldBindings(scope); + } + // thus it was a type + bits &= ~RestrictiveFlagMASK; // clear bits + bits |= TYPE; + case TYPE : //=============only type ============== + if (isTypeUseDeprecated((TypeBinding) binding, scope)) + scope.problemReporter().deprecatedType((TypeBinding) binding, this); + return this.resolvedType = (TypeBinding) binding; + } + } + //========error cases=============== + return this.resolvedType = this.reportError(scope); + } + + public void setFieldIndex(int index) { + this.indexOfFirstFieldBinding = index; + } + + public void traverse(ASTVisitor visitor, BlockScope scope) { + visitor.visit(this, scope); + visitor.endVisit(this, scope); + } + public String unboundReferenceErrorName() { + return new String(tokens[0]); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/QualifiedSuperReference.java b/src/java/org/eclipse/jdt/internal/compiler/ast/QualifiedSuperReference.java new file mode 100644 index 0000000..592c433 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/QualifiedSuperReference.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class QualifiedSuperReference extends QualifiedThisReference { + + public QualifiedSuperReference(TypeReference name, int pos, int sourceEnd) { + super(name, pos, sourceEnd); + } + + public boolean isSuper() { + + return true; + } + + public boolean isThis() { + + return false; + } + + public StringBuffer printExpression(int indent, StringBuffer output) { + + return qualification.print(0, output).append(".super"); //$NON-NLS-1$ + } + + public TypeBinding resolveType(BlockScope scope) { + + if ((this.bits & ParenthesizedMASK) != 0) { + scope.problemReporter().invalidParenthesizedExpression(this); + return null; + } + super.resolveType(scope); + if (currentCompatibleType == null) + return null; // error case + + if (currentCompatibleType.id == T_Object) { + scope.problemReporter().cannotUseSuperInJavaLangObject(this); + return null; + } + return this.resolvedType = currentCompatibleType.superclass(); + } + + public void traverse( + ASTVisitor visitor, + BlockScope blockScope) { + + if (visitor.visit(this, blockScope)) { + qualification.traverse(visitor, blockScope); + } + visitor.endVisit(this, blockScope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/QualifiedThisReference.java b/src/java/org/eclipse/jdt/internal/compiler/ast/QualifiedThisReference.java new file mode 100644 index 0000000..93e4c1c --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/QualifiedThisReference.java @@ -0,0 +1,116 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class QualifiedThisReference extends ThisReference { + + public TypeReference qualification; + ReferenceBinding currentCompatibleType; + + public QualifiedThisReference(TypeReference name, int sourceStart, int sourceEnd) { + super(sourceStart, sourceEnd); + qualification = name; + this.sourceStart = name.sourceStart; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + return flowInfo; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo, + boolean valueRequired) { + + return flowInfo; + } + + /** + * Code generation for QualifiedThisReference + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ + public void generateCode( + BlockScope currentScope, + CodeStream codeStream, + boolean valueRequired) { + + int pc = codeStream.position; + if (valueRequired) { + if ((bits & DepthMASK) != 0) { + Object[] emulationPath = + currentScope.getEmulationPath(this.currentCompatibleType, true /*only exact match*/, false/*consider enclosing arg*/); + codeStream.generateOuterAccess(emulationPath, this, this.currentCompatibleType, currentScope); + } else { + // nothing particular after all + codeStream.aload_0(); + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public TypeBinding resolveType(BlockScope scope) { + + constant = NotAConstant; + this.resolvedType = this.qualification.resolveType(scope); + if (this.resolvedType == null) return null; + + // the qualification MUST exactly match some enclosing type name + // Its possible to qualify 'this' by the name of the current class + int depth = 0; + this.currentCompatibleType = scope.referenceType().binding; + while (this.currentCompatibleType != null + && this.currentCompatibleType != this.resolvedType) { + depth++; + this.currentCompatibleType = this.currentCompatibleType.isStatic() ? null : this.currentCompatibleType.enclosingType(); + } + bits &= ~DepthMASK; // flush previous depth if any + bits |= (depth & 0xFF) << DepthSHIFT; // encoded depth into 8 bits + + if (this.currentCompatibleType == null) { + scope.problemReporter().noSuchEnclosingInstance(this.resolvedType, this, false); + return this.resolvedType; + } + + // Ensure one cannot write code like: B() { super(B.this); } + if (depth == 0) { + checkAccess(scope.methodScope()); + } // if depth>0, path emulation will diagnose bad scenarii + return this.resolvedType; + } + + public StringBuffer printExpression(int indent, StringBuffer output) { + + return qualification.print(0, output).append(".this"); //$NON-NLS-1$ + } + + public void traverse( + ASTVisitor visitor, + BlockScope blockScope) { + + if (visitor.visit(this, blockScope)) { + qualification.traverse(visitor, blockScope); + } + visitor.endVisit(this, blockScope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java b/src/java/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java new file mode 100644 index 0000000..b37276b --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class QualifiedTypeReference extends TypeReference { + + public char[][] tokens; + public long[] sourcePositions; + + public QualifiedTypeReference(char[][] sources , long[] poss) { + + tokens = sources ; + sourcePositions = poss ; + sourceStart = (int) (sourcePositions[0]>>>32) ; + sourceEnd = (int)(sourcePositions[sourcePositions.length-1] & 0x00000000FFFFFFFFL ) ; + } + + public QualifiedTypeReference(char[][] sources , TypeBinding type , long[] poss) { + + this(sources,poss); + this.resolvedType = type; + } + + public TypeReference copyDims(int dim){ + //return a type reference copy of me with some dimensions + //warning : the new type ref has a null binding + return new ArrayQualifiedTypeReference(tokens,null,dim,sourcePositions) ; + } + + public TypeBinding getTypeBinding(Scope scope) { + + if (this.resolvedType != null) + return this.resolvedType; + return scope.getType(tokens); + } + + public char[][] getTypeName(){ + + return tokens; + } + + public StringBuffer printExpression(int indent, StringBuffer output) { + + for (int i = 0; i < tokens.length; i++) { + if (i > 0) output.append('.'); + output.append(tokens[i]); + } + return output; + } + + public void traverse(ASTVisitor visitor, BlockScope scope) { + + visitor.visit(this, scope); + visitor.endVisit(this, scope); + } + + public void traverse(ASTVisitor visitor, ClassScope scope) { + + visitor.visit(this, scope); + visitor.endVisit(this, scope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/Reference.java b/src/java/org/eclipse/jdt/internal/compiler/ast/Reference.java new file mode 100644 index 0000000..41d498b --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/Reference.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public abstract class Reference extends Expression { +/** + * BaseLevelReference constructor comment. + */ +public Reference() { + super(); +} +public abstract FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound); + +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + return flowInfo; +} +public FieldBinding fieldBinding() { + //this method should be sent one FIELD-tagged references + // (ref.bits & BindingIds.FIELD != 0)() + return null ; +} +public void fieldStore(CodeStream codeStream, FieldBinding fieldBinding, MethodBinding syntheticWriteAccessor, boolean valueRequired) { + + if (fieldBinding.isStatic()) { + if (valueRequired) { + if ((fieldBinding.type == LongBinding) || (fieldBinding.type == DoubleBinding)) { + codeStream.dup2(); + } else { + codeStream.dup(); + } + } + if (syntheticWriteAccessor == null) { + codeStream.putstatic(fieldBinding); + } else { + codeStream.invokestatic(syntheticWriteAccessor); + } + } else { // Stack: [owner][new field value] ---> [new field value][owner][new field value] + if (valueRequired) { + if ((fieldBinding.type == LongBinding) || (fieldBinding.type == DoubleBinding)) { + codeStream.dup2_x1(); + } else { + codeStream.dup_x1(); + } + } + if (syntheticWriteAccessor == null) { + codeStream.putfield(fieldBinding); + } else { + codeStream.invokestatic(syntheticWriteAccessor); + } + } +} +public abstract void generateAssignment(BlockScope currentScope, CodeStream codeStream, Assignment assignment, boolean valueRequired); + +public abstract void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired); + +public abstract void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired); + +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java b/src/java/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java new file mode 100644 index 0000000..ca74dae --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java @@ -0,0 +1,238 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class ReturnStatement extends Statement { + + public Expression expression; + public TypeBinding expressionType; + public boolean isSynchronized; + public SubRoutineStatement[] subroutines; + public boolean isAnySubRoutineEscaping = false; + public LocalVariableBinding saveValueVariable; + + public ReturnStatement(Expression expr, int s, int e ) { + sourceStart = s; + sourceEnd = e; + expression = expr ; + } + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { // here requires to generate a sequence of finally blocks invocations depending corresponding + // to each of the traversed try statements, so that execution will terminate properly. + + // lookup the label, this should answer the returnContext + + if (expression != null) { + flowInfo = expression.analyseCode(currentScope, flowContext, flowInfo); + } + // compute the return sequence (running the finally blocks) + FlowContext traversedContext = flowContext; + int subIndex = 0, maxSub = 5; + boolean saveValueNeeded = false; + boolean hasValueToSave = expression != null && expression.constant == NotAConstant; + do { + SubRoutineStatement sub; + if ((sub = traversedContext.subRoutine()) != null) { + if (this.subroutines == null){ + this.subroutines = new SubRoutineStatement[maxSub]; + } + if (subIndex == maxSub) { + System.arraycopy(this.subroutines, 0, (this.subroutines = new SubRoutineStatement[maxSub *= 2]), 0, subIndex); // grow + } + this.subroutines[subIndex++] = sub; + if (sub.isSubRoutineEscaping()) { + saveValueNeeded = false; + isAnySubRoutineEscaping = true; + break; + } + } + traversedContext.recordReturnFrom(flowInfo.unconditionalInits()); + + ASTNode node; + if ((node = traversedContext.associatedNode) instanceof SynchronizedStatement) { + isSynchronized = true; + + } else if (node instanceof TryStatement) { + TryStatement tryStatement = (TryStatement) node; + flowInfo.addInitializationsFrom(tryStatement.subRoutineInits); // collect inits + if (hasValueToSave) { + if (this.saveValueVariable == null){ // closest subroutine secret variable is used + prepareSaveValueLocation(tryStatement); + } + saveValueNeeded = true; + } + + } else if (traversedContext instanceof InitializationFlowContext) { + currentScope.problemReporter().cannotReturnInInitializer(this); + return FlowInfo.DEAD_END; + } + } while ((traversedContext = traversedContext.parent) != null); + + // resize subroutines + if ((subroutines != null) && (subIndex != maxSub)) { + System.arraycopy(subroutines, 0, (subroutines = new SubRoutineStatement[subIndex]), 0, subIndex); + } + + // secret local variable for return value (note that this can only occur in a real method) + if (saveValueNeeded) { + if (this.saveValueVariable != null) { + this.saveValueVariable.useFlag = LocalVariableBinding.USED; + } + } else { + this.saveValueVariable = null; + if ((!isSynchronized) && (expressionType == BooleanBinding)) { + this.expression.bits |= ValueForReturnMASK; + } + } + return FlowInfo.DEAD_END; + } + + /** + * Retrun statement code generation + * + * generate the finallyInvocationSequence. + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + if ((bits & IsReachableMASK) == 0) { + return; + } + int pc = codeStream.position; + // generate the expression + if ((expression != null) && (expression.constant == NotAConstant)) { + expression.generateCode(currentScope, codeStream, needValue()); // no value needed if non-returning subroutine + generateStoreSaveValueIfNecessary(codeStream); + } + + // generation of code responsible for invoking the finally blocks in sequence + if (subroutines != null) { + for (int i = 0, max = subroutines.length; i < max; i++) { + SubRoutineStatement sub = subroutines[i]; + sub.generateSubRoutineInvocation(currentScope, codeStream); + if (sub.isSubRoutineEscaping()) { + codeStream.recordPositionsFrom(pc, this.sourceStart); + SubRoutineStatement.reenterExceptionHandlers(subroutines, i, codeStream); + return; + } + sub.exitAnyExceptionHandler(); + } + } + if (saveValueVariable != null) codeStream.load(saveValueVariable); + + if ((expression != null) && (expression.constant != NotAConstant)) { + codeStream.generateConstant(expression.constant, expression.implicitConversion); + generateStoreSaveValueIfNecessary(codeStream); + } + // output the suitable return bytecode or wrap the value inside a descriptor for doits + this.generateReturnBytecode(codeStream); + codeStream.recordPositionsFrom(pc, this.sourceStart); + SubRoutineStatement.reenterExceptionHandlers(subroutines, -1, codeStream); + } + /** + * Dump the suitable return bytecode for a return statement + * + */ + public void generateReturnBytecode(CodeStream codeStream) { + + if (expression == null) { + codeStream.return_(); + } else { + switch (expression.implicitConversion >> 4) { + case T_boolean : + case T_int : + codeStream.ireturn(); + break; + case T_float : + codeStream.freturn(); + break; + case T_long : + codeStream.lreturn(); + break; + case T_double : + codeStream.dreturn(); + break; + default : + codeStream.areturn(); + } + } + } + public void generateStoreSaveValueIfNecessary(CodeStream codeStream){ + if (saveValueVariable != null) codeStream.store(saveValueVariable, false); + } + public boolean needValue(){ + return (subroutines == null) || (saveValueVariable != null) || isSynchronized; + } + public void prepareSaveValueLocation(TryStatement targetTryStatement){ + + this.saveValueVariable = targetTryStatement.secretReturnValue; + } + public StringBuffer printStatement(int tab, StringBuffer output){ + + printIndent(tab, output).append("return "); //$NON-NLS-1$ + if (expression != null ) + expression.printExpression(0, output) ; + return output.append(';'); + } + public void resolve(BlockScope scope) { + MethodScope methodScope = scope.methodScope(); + MethodBinding methodBinding; + TypeBinding methodType = + (methodScope.referenceContext instanceof AbstractMethodDeclaration) + ? ((methodBinding = ((AbstractMethodDeclaration) methodScope.referenceContext).binding) == null + ? null + : methodBinding.returnType) + : VoidBinding; + if (methodType == VoidBinding) { + // the expression should be null + if (expression == null) + return; + if ((expressionType = expression.resolveType(scope)) != null) + scope.problemReporter().attemptToReturnNonVoidExpression(this, expressionType); + return; + } + if (expression == null) { + if (methodType != null) scope.problemReporter().shouldReturn(methodType, this); + return; + } + if ((expressionType = expression.resolveType(scope)) == null) + return; + + if (methodType != null && expression.isConstantValueOfTypeAssignableToType(expressionType, methodType)) { + // dealing with constant + expression.implicitWidening(methodType, expressionType); + return; + } + if (expressionType == VoidBinding) { + scope.problemReporter().attemptToReturnVoidValue(this); + return; + } + if (methodType != null && expressionType.isCompatibleWith(methodType)) { + expression.implicitWidening(methodType, expressionType); + return; + } + if (methodType != null){ + scope.problemReporter().typeMismatchErrorActualTypeExpectedType(expression, expressionType, methodType); + } + } + public void traverse(ASTVisitor visitor, BlockScope scope) { + if (visitor.visit(this, scope)) { + if (expression != null) + expression.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java b/src/java/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java new file mode 100644 index 0000000..908732b --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java @@ -0,0 +1,687 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; +import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; + +public class SingleNameReference extends NameReference implements OperatorIds { + public char[] token; + + public MethodBinding[] syntheticAccessors; // [0]=read accessor [1]=write accessor + public static final int READ = 0; + public static final int WRITE = 1; + + public SingleNameReference(char[] source, long pos) { + super(); + token = source; + sourceStart = (int) (pos >>> 32); + sourceEnd = (int) pos; + } + public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound) { + + boolean isReachable = flowInfo.isReachable(); + // compound assignment extra work + if (isCompound) { // check the variable part is initialized if blank final + switch (bits & RestrictiveFlagMASK) { + case FIELD : // reading a field + FieldBinding fieldBinding; + if ((fieldBinding = (FieldBinding) binding).isBlankFinal() + && currentScope.allowBlankFinalFieldAssignment(fieldBinding)) { + if (!flowInfo.isDefinitelyAssigned(fieldBinding)) { + currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this); + } + } + manageSyntheticReadAccessIfNecessary(currentScope, flowInfo); + break; + case LOCAL : // reading a local variable + // check if assigning a final blank field + LocalVariableBinding localBinding; + if (!flowInfo.isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) { + currentScope.problemReporter().uninitializedLocalVariable(localBinding, this); + // we could improve error msg here telling "cannot use compound assignment on final local variable" + } + if (isReachable) { + localBinding.useFlag = LocalVariableBinding.USED; + } else if (localBinding.useFlag == LocalVariableBinding.UNUSED) { + localBinding.useFlag = LocalVariableBinding.FAKE_USED; + } + } + } + if (assignment.expression != null) { + flowInfo = assignment.expression.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); + } + switch (bits & RestrictiveFlagMASK) { + case FIELD : // assigning to a field + manageSyntheticWriteAccessIfNecessary(currentScope, flowInfo); + + // check if assigning a final field + FieldBinding fieldBinding; + if ((fieldBinding = (FieldBinding) binding).isFinal()) { + // inside a context where allowed + if (!isCompound && fieldBinding.isBlankFinal() && currentScope.allowBlankFinalFieldAssignment(fieldBinding)) { + if (flowInfo.isPotentiallyAssigned(fieldBinding)) { + currentScope.problemReporter().duplicateInitializationOfBlankFinalField(fieldBinding, this); + } else { + flowContext.recordSettingFinal(fieldBinding, this, flowInfo); + } + flowInfo.markAsDefinitelyAssigned(fieldBinding); + } else { + currentScope.problemReporter().cannotAssignToFinalField(fieldBinding, this); + } + } + break; + case LOCAL : // assigning to a local variable + LocalVariableBinding localBinding = (LocalVariableBinding) binding; + if (!flowInfo.isDefinitelyAssigned(localBinding)){// for local variable debug attributes + bits |= FirstAssignmentToLocalMASK; + } else { + bits &= ~FirstAssignmentToLocalMASK; + } + if (localBinding.isFinal()) { + if ((bits & DepthMASK) == 0) { + // tolerate assignment to final local in unreachable code (45674) + if ((isReachable && isCompound) || !localBinding.isBlankFinal()){ + currentScope.problemReporter().cannotAssignToFinalLocal(localBinding, this); + } else if (flowInfo.isPotentiallyAssigned(localBinding)) { + currentScope.problemReporter().duplicateInitializationOfFinalLocal(localBinding, this); + } else { + flowContext.recordSettingFinal(localBinding, this, flowInfo); + } + } else { + currentScope.problemReporter().cannotAssignToFinalOuterLocal(localBinding, this); + } + } + flowInfo.markAsDefinitelyAssigned(localBinding); + } + manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo); + return flowInfo; + } + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + return analyseCode(currentScope, flowContext, flowInfo, true); + } + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { + + switch (bits & RestrictiveFlagMASK) { + case FIELD : // reading a field + if (valueRequired) { + manageSyntheticReadAccessIfNecessary(currentScope, flowInfo); + } + // check if reading a final blank field + FieldBinding fieldBinding; + if ((fieldBinding = (FieldBinding) binding).isBlankFinal() + && currentScope.allowBlankFinalFieldAssignment(fieldBinding)) { + if (!flowInfo.isDefinitelyAssigned(fieldBinding)) { + currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this); + } + } + break; + case LOCAL : // reading a local variable + LocalVariableBinding localBinding; + if (!flowInfo.isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) { + currentScope.problemReporter().uninitializedLocalVariable(localBinding, this); + } + if (flowInfo.isReachable()) { + localBinding.useFlag = LocalVariableBinding.USED; + } else if (localBinding.useFlag == LocalVariableBinding.UNUSED) { + localBinding.useFlag = LocalVariableBinding.FAKE_USED; + } + } + if (valueRequired) { + manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo); + } + return flowInfo; + } + public TypeBinding checkFieldAccess(BlockScope scope) { + + FieldBinding fieldBinding = (FieldBinding) binding; + + bits &= ~RestrictiveFlagMASK; // clear bits + bits |= FIELD; + if (!((FieldBinding) binding).isStatic()) { + // must check for the static status.... + if (scope.methodScope().isStatic) { + scope.problemReporter().staticFieldAccessToNonStaticVariable(this, fieldBinding); + constant = NotAConstant; + return fieldBinding.type; + } + } + constant = FieldReference.getConstantFor(fieldBinding, this, true, scope); + + if (isFieldUseDeprecated(fieldBinding, scope, (this.bits & IsStrictlyAssignedMASK) !=0)) + scope.problemReporter().deprecatedField(fieldBinding, this); + + MethodScope ms = scope.methodScope(); + if ((this.bits & IsStrictlyAssignedMASK) == 0 + && ms.enclosingSourceType() == fieldBinding.declaringClass + && ms.lastVisibleFieldID >= 0 + && fieldBinding.id >= ms.lastVisibleFieldID) { + //if the field is static and ms is not .... then it is valid + if (!fieldBinding.isStatic() || ms.isStatic) + scope.problemReporter().forwardReference(this, 0, scope.enclosingSourceType()); + } + //==================================================== + + return fieldBinding.type; + + } + public void generateAssignment(BlockScope currentScope, CodeStream codeStream, Assignment assignment, boolean valueRequired) { + + // optimizing assignment like: i = i + 1 or i = 1 + i + if (assignment.expression.isCompactableOperation()) { + BinaryExpression operation = (BinaryExpression) assignment.expression; + SingleNameReference variableReference; + if ((operation.left instanceof SingleNameReference) && ((variableReference = (SingleNameReference) operation.left).binding == binding)) { + // i = i + value, then use the variable on the right hand side, since it has the correct implicit conversion + variableReference.generateCompoundAssignment(currentScope, codeStream, syntheticAccessors == null ? null : syntheticAccessors[WRITE], operation.right, (operation.bits & OperatorMASK) >> OperatorSHIFT, operation.left.implicitConversion /*should be equivalent to no conversion*/, valueRequired); + return; + } + int operator = (operation.bits & OperatorMASK) >> OperatorSHIFT; + if ((operation.right instanceof SingleNameReference) + && ((operator == PLUS) || (operator == MULTIPLY)) // only commutative operations + && ((variableReference = (SingleNameReference) operation.right).binding == binding) + && (operation.left.constant != NotAConstant) // exclude non constant expressions, since could have side-effect + && ((operation.left.implicitConversion >> 4) != T_String) // exclude string concatenation which would occur backwards + && ((operation.right.implicitConversion >> 4) != T_String)) { // exclude string concatenation which would occur backwards + // i = value + i, then use the variable on the right hand side, since it has the correct implicit conversion + variableReference.generateCompoundAssignment(currentScope, codeStream, syntheticAccessors == null ? null : syntheticAccessors[WRITE], operation.left, operator, operation.right.implicitConversion /*should be equivalent to no conversion*/, valueRequired); + return; + } + } + switch (bits & RestrictiveFlagMASK) { + case FIELD : // assigning to a field + FieldBinding fieldBinding; + if (!(fieldBinding = (FieldBinding) this.codegenBinding).isStatic()) { // need a receiver? + if ((bits & DepthMASK) != 0) { + ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT); + Object[] emulationPath = currentScope.getEmulationPath(targetType, true /*only exact match*/, false/*consider enclosing arg*/); + codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope); + } else { + this.generateReceiver(codeStream); + } + } + assignment.expression.generateCode(currentScope, codeStream, true); + fieldStore(codeStream, fieldBinding, syntheticAccessors == null ? null : syntheticAccessors[WRITE], valueRequired); + if (valueRequired) { + codeStream.generateImplicitConversion(assignment.implicitConversion); + } + return; + case LOCAL : // assigning to a local variable + LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding; + if (localBinding.resolvedPosition != -1) { + assignment.expression.generateCode(currentScope, codeStream, true); + } else { + if (assignment.expression.constant != NotAConstant) { + // assigning an unused local to a constant value = no actual assignment is necessary + if (valueRequired) { + codeStream.generateConstant(assignment.expression.constant, assignment.implicitConversion); + } + } else { + assignment.expression.generateCode(currentScope, codeStream, true); + /* Even though the value may not be required, we force it to be produced, and discard it later + on if it was actually not necessary, so as to provide the same behavior as JDK1.2beta3. */ + if (valueRequired) { + codeStream.generateImplicitConversion(assignment.implicitConversion); // implicit conversion + } else { + if ((localBinding.type == LongBinding) || (localBinding.type == DoubleBinding)) { + codeStream.pop2(); + } else { + codeStream.pop(); + } + } + } + return; + } + // 26903, need extra cast to store null in array local var + if (localBinding.type.isArrayType() + && (assignment.expression.resolvedType == NullBinding // arrayLoc = null + || ((assignment.expression instanceof CastExpression) // arrayLoc = (type[])null + && (((CastExpression)assignment.expression).innermostCastedExpression().resolvedType == NullBinding)))){ + codeStream.checkcast(localBinding.type); + } + + // normal local assignment (since cannot store in outer local which are final locations) + codeStream.store(localBinding, valueRequired); + if ((bits & FirstAssignmentToLocalMASK) != 0) { // for local variable debug attributes + localBinding.recordInitializationStartPC(codeStream.position); + } + // implicit conversion + if (valueRequired) { + codeStream.generateImplicitConversion(assignment.implicitConversion); + } + } + } + public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { + int pc = codeStream.position; + if (constant != NotAConstant) { + if (valueRequired) { + codeStream.generateConstant(constant, implicitConversion); + } + } else { + switch (bits & RestrictiveFlagMASK) { + case FIELD : // reading a field + FieldBinding fieldBinding; + if (valueRequired) { + if ((fieldBinding = (FieldBinding) this.codegenBinding).constant == NotAConstant) { // directly use inlined value for constant fields + boolean isStatic; + if (!(isStatic = fieldBinding.isStatic())) { + if ((bits & DepthMASK) != 0) { + ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT); + Object[] emulationPath = currentScope.getEmulationPath(targetType, true /*only exact match*/, false/*consider enclosing arg*/); + codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope); + } else { + generateReceiver(codeStream); + } + } + // managing private access + if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) { + if (isStatic) { + codeStream.getstatic(fieldBinding); + } else { + codeStream.getfield(fieldBinding); + } + } else { + codeStream.invokestatic(syntheticAccessors[READ]); + } + codeStream.generateImplicitConversion(implicitConversion); + } else { // directly use the inlined value + codeStream.generateConstant(fieldBinding.constant, implicitConversion); + } + } + break; + case LOCAL : // reading a local + LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding; + if (valueRequired) { + // outer local? + if ((bits & DepthMASK) != 0) { + // outer local can be reached either through a synthetic arg or a synthetic field + VariableBinding[] path = currentScope.getEmulationPath(localBinding); + codeStream.generateOuterAccess(path, this, localBinding, currentScope); + } else { + // regular local variable read + codeStream.load(localBinding); + } + codeStream.generateImplicitConversion(implicitConversion); + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + /* + * Regular API for compound assignment, relies on the fact that there is only one reference to the + * variable, which carries both synthetic read/write accessors. + * The APIs with an extra argument is used whenever there are two references to the same variable which + * are optimized in one access: e.g "a = a + 1" optimized into "a++". + */ + public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) { + + this.generateCompoundAssignment( + currentScope, + codeStream, + syntheticAccessors == null ? null : syntheticAccessors[WRITE], + expression, + operator, + assignmentImplicitConversion, + valueRequired); + } + /* + * The APIs with an extra argument is used whenever there are two references to the same variable which + * are optimized in one access: e.g "a = a + 1" optimized into "a++". + */ + public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, MethodBinding writeAccessor, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) { + switch (bits & RestrictiveFlagMASK) { + case FIELD : // assigning to a field + FieldBinding fieldBinding; + if ((fieldBinding = (FieldBinding) this.codegenBinding).isStatic()) { + if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) { + codeStream.getstatic(fieldBinding); + } else { + codeStream.invokestatic(syntheticAccessors[READ]); + } + } else { + if ((bits & DepthMASK) != 0) { + ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT); + Object[] emulationPath = currentScope.getEmulationPath(targetType, true /*only exact match*/, false/*consider enclosing arg*/); + codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope); + } else { + codeStream.aload_0(); + } + codeStream.dup(); + if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) { + codeStream.getfield(fieldBinding); + } else { + codeStream.invokestatic(syntheticAccessors[READ]); + } + } + break; + case LOCAL : // assigning to a local variable (cannot assign to outer local) + LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding; + Constant assignConstant; + int increment; + // using incr bytecode if possible + switch (localBinding.type.id) { + case T_String : + codeStream.generateStringAppend(currentScope, this, expression); + if (valueRequired) { + codeStream.dup(); + } + codeStream.store(localBinding, false); + return; + case T_int : + if (((assignConstant = expression.constant) != NotAConstant) + && (assignConstant.typeID() != T_float) // only for integral types + && (assignConstant.typeID() != T_double) + && ((increment = assignConstant.intValue()) == (short) increment)) { // 16 bits value + switch (operator) { + case PLUS : + codeStream.iinc(localBinding.resolvedPosition, increment); + if (valueRequired) { + codeStream.load(localBinding); + } + return; + case MINUS : + codeStream.iinc(localBinding.resolvedPosition, -increment); + if (valueRequired) { + codeStream.load(localBinding); + } + return; + } + } + default : + codeStream.load(localBinding); + } + } + // perform the actual compound operation + int operationTypeID; + if ((operationTypeID = implicitConversion >> 4) == T_String || operationTypeID == T_Object) { + // we enter here if the single name reference is a field of type java.lang.String or if the type of the + // operation is java.lang.Object + // For example: o = o + ""; // where the compiled type of o is java.lang.Object. + codeStream.generateStringAppend(currentScope, null, expression); + } else { + // promote the array reference to the suitable operation type + codeStream.generateImplicitConversion(implicitConversion); + // generate the increment value (will by itself be promoted to the operation value) + if (expression == IntLiteral.One){ // prefix operation + codeStream.generateConstant(expression.constant, implicitConversion); + } else { + expression.generateCode(currentScope, codeStream, true); + } + // perform the operation + codeStream.sendOperator(operator, operationTypeID); + // cast the value back to the array reference type + codeStream.generateImplicitConversion(assignmentImplicitConversion); + } + // store the result back into the variable + switch (bits & RestrictiveFlagMASK) { + case FIELD : // assigning to a field + fieldStore(codeStream, (FieldBinding) this.codegenBinding, writeAccessor, valueRequired); + return; + case LOCAL : // assigning to a local variable + LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding; + if (valueRequired) { + if ((localBinding.type == LongBinding) || (localBinding.type == DoubleBinding)) { + codeStream.dup2(); + } else { + codeStream.dup(); + } + } + codeStream.store(localBinding, false); + } + } + + public void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired) { + switch (bits & RestrictiveFlagMASK) { + case FIELD : // assigning to a field + FieldBinding fieldBinding; + if ((fieldBinding = (FieldBinding) this.codegenBinding).isStatic()) { + if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) { + codeStream.getstatic(fieldBinding); + } else { + codeStream.invokestatic(syntheticAccessors[READ]); + } + } else { + if ((bits & DepthMASK) != 0) { + ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT); + Object[] emulationPath = currentScope.getEmulationPath(targetType, true /*only exact match*/, false/*consider enclosing arg*/); + codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope); + } else { + codeStream.aload_0(); + } + codeStream.dup(); + if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) { + codeStream.getfield(fieldBinding); + } else { + codeStream.invokestatic(syntheticAccessors[READ]); + } + } + if (valueRequired) { + if (fieldBinding.isStatic()) { + if ((fieldBinding.type == LongBinding) || (fieldBinding.type == DoubleBinding)) { + codeStream.dup2(); + } else { + codeStream.dup(); + } + } else { // Stack: [owner][old field value] ---> [old field value][owner][old field value] + if ((fieldBinding.type == LongBinding) || (fieldBinding.type == DoubleBinding)) { + codeStream.dup2_x1(); + } else { + codeStream.dup_x1(); + } + } + } + codeStream.generateConstant(postIncrement.expression.constant, implicitConversion); + codeStream.sendOperator(postIncrement.operator, fieldBinding.type.id); + codeStream.generateImplicitConversion(postIncrement.assignmentImplicitConversion); + fieldStore(codeStream, fieldBinding, syntheticAccessors == null ? null : syntheticAccessors[WRITE], false); + return; + case LOCAL : // assigning to a local variable + LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding; + // using incr bytecode if possible + if (localBinding.type == IntBinding) { + if (valueRequired) { + codeStream.load(localBinding); + } + if (postIncrement.operator == PLUS) { + codeStream.iinc(localBinding.resolvedPosition, 1); + } else { + codeStream.iinc(localBinding.resolvedPosition, -1); + } + } else { + codeStream.load(localBinding); + if (valueRequired){ + if ((localBinding.type == LongBinding) || (localBinding.type == DoubleBinding)) { + codeStream.dup2(); + } else { + codeStream.dup(); + } + } + codeStream.generateConstant(postIncrement.expression.constant, implicitConversion); + codeStream.sendOperator(postIncrement.operator, localBinding.type.id); + codeStream.generateImplicitConversion(postIncrement.assignmentImplicitConversion); + + codeStream.store(localBinding, false); + } + } + } + + public void generateReceiver(CodeStream codeStream) { + + codeStream.aload_0(); + } + + public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) { + + if (!flowInfo.isReachable()) return; + //If inlinable field, forget the access emulation, the code gen will directly target it + if (((bits & DepthMASK) == 0) || (constant != NotAConstant)) return; + + if ((bits & RestrictiveFlagMASK) == LOCAL) { + currentScope.emulateOuterAccess((LocalVariableBinding) binding); + } + } + public void manageSyntheticReadAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) { + + if (!flowInfo.isReachable()) return; + + //If inlinable field, forget the access emulation, the code gen will directly target it + if (constant != NotAConstant) + return; + + if ((bits & FIELD) != 0) { + FieldBinding fieldBinding = (FieldBinding) binding; + if (((bits & DepthMASK) != 0) + && (fieldBinding.isPrivate() // private access + || (fieldBinding.isProtected() // implicit protected access + && fieldBinding.declaringClass.getPackage() + != currentScope.enclosingSourceType().getPackage()))) { + if (syntheticAccessors == null) + syntheticAccessors = new MethodBinding[2]; + syntheticAccessors[READ] = + ((SourceTypeBinding)currentScope.enclosingSourceType(). + enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT)). + addSyntheticMethod(fieldBinding, true); + currentScope.problemReporter().needToEmulateFieldReadAccess(fieldBinding, this); + return; + } + // if the binding declaring class is not visible, need special action + // for runtime compatibility on 1.2 VMs : change the declaring class of the binding + // NOTE: from target 1.2 on, field's declaring class is touched if any different from receiver type + // and not from Object or implicit static field access. + if (fieldBinding.declaringClass != this.actualReceiverType + && !this.actualReceiverType.isArrayType() + && fieldBinding.declaringClass != null + && fieldBinding.constant == NotAConstant + && ((currentScope.environment().options.targetJDK >= ClassFileConstants.JDK1_2 + && !fieldBinding.isStatic() + && fieldBinding.declaringClass.id != T_Object) // no change for Object fields (if there was any) + || !fieldBinding.declaringClass.canBeSeenBy(currentScope))){ + this.codegenBinding = currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding, (ReferenceBinding)this.actualReceiverType); + } + } + } + public void manageSyntheticWriteAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) { + + if (!flowInfo.isReachable()) return; + if ((bits & FIELD) != 0) { + FieldBinding fieldBinding = (FieldBinding) binding; + if (((bits & DepthMASK) != 0) + && (fieldBinding.isPrivate() // private access + || (fieldBinding.isProtected() // implicit protected access + && fieldBinding.declaringClass.getPackage() + != currentScope.enclosingSourceType().getPackage()))) { + if (syntheticAccessors == null) + syntheticAccessors = new MethodBinding[2]; + syntheticAccessors[WRITE] = + ((SourceTypeBinding)currentScope.enclosingSourceType(). + enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT)). + addSyntheticMethod(fieldBinding, false); + currentScope.problemReporter().needToEmulateFieldWriteAccess(fieldBinding, this); + return; + } + // if the binding declaring class is not visible, need special action + // for runtime compatibility on 1.2 VMs : change the declaring class of the binding + // NOTE: from target 1.2 on, field's declaring class is touched if any different from receiver type + // and not from Object or implicit static field access. + if (fieldBinding.declaringClass != this.actualReceiverType + && !this.actualReceiverType.isArrayType() + && fieldBinding.declaringClass != null + && fieldBinding.constant == NotAConstant + && ((currentScope.environment().options.targetJDK >= ClassFileConstants.JDK1_2 + && !fieldBinding.isStatic() + && fieldBinding.declaringClass.id != T_Object) // no change for Object fields (if there was any) + || !fieldBinding.declaringClass.canBeSeenBy(currentScope))){ + this.codegenBinding = currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding, (ReferenceBinding)this.actualReceiverType); + } + } + } + public StringBuffer printExpression(int indent, StringBuffer output){ + + return output.append(token); + } + + public TypeBinding reportError(BlockScope scope) { + + //=====error cases======= + constant = Constant.NotAConstant; + if (binding instanceof ProblemFieldBinding) { + scope.problemReporter().invalidField(this, (FieldBinding) binding); + } else if (binding instanceof ProblemReferenceBinding) { + scope.problemReporter().invalidType(this, (TypeBinding) binding); + } else { + scope.problemReporter().unresolvableReference(this, binding); + } + return null; + } + public TypeBinding resolveType(BlockScope scope) { + // for code gen, harm the restrictiveFlag + + this.actualReceiverType = this.receiverType = scope.enclosingSourceType(); + + if ((this.codegenBinding = this.binding = scope.getBinding(token, bits & RestrictiveFlagMASK, this, true /*resolve*/)).isValidBinding()) { + switch (bits & RestrictiveFlagMASK) { + case VARIABLE : // =========only variable============ + case VARIABLE | TYPE : //====both variable and type============ + if (binding instanceof VariableBinding) { + VariableBinding variable = (VariableBinding) binding; + if (binding instanceof LocalVariableBinding) { + bits &= ~RestrictiveFlagMASK; // clear bits + bits |= LOCAL; + if ((this.bits & IsStrictlyAssignedMASK) == 0) { + constant = variable.constant; + } else { + constant = NotAConstant; + } + if (!variable.isFinal() && (bits & DepthMASK) != 0) { + scope.problemReporter().cannotReferToNonFinalOuterLocal((LocalVariableBinding)variable, this); + } + return this.resolvedType = variable.type; + } + // a field + FieldBinding field = (FieldBinding) this.binding; + if (!field.isStatic() && scope.environment().options.getSeverity(CompilerOptions.UnqualifiedFieldAccess) != ProblemSeverities.Ignore) { + scope.problemReporter().unqualifiedFieldAccess(this, field); + } + return this.resolvedType = checkFieldAccess(scope); + } + + // thus it was a type + bits &= ~RestrictiveFlagMASK; // clear bits + bits |= TYPE; + case TYPE : //========only type============== + constant = Constant.NotAConstant; + //deprecated test + if (isTypeUseDeprecated((TypeBinding) binding, scope)) + scope.problemReporter().deprecatedType((TypeBinding) binding, this); + return this.resolvedType = (TypeBinding) binding; + } + } + + // error scenarii + return this.resolvedType = this.reportError(scope); + } + + public void traverse(ASTVisitor visitor, BlockScope scope) { + + visitor.visit(this, scope); + visitor.endVisit(this, scope); + } + + public String unboundReferenceErrorName(){ + + return new String(token); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java b/src/java/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java new file mode 100644 index 0000000..4d29467 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class SingleTypeReference extends TypeReference { + + public char[] token; + + public SingleTypeReference(char[] source, long pos) { + + token = source; + sourceStart = (int) (pos>>>32) ; + sourceEnd = (int) (pos & 0x00000000FFFFFFFFL) ; + + } + + public SingleTypeReference(char[] source ,TypeBinding type, long pos) { + this(source, pos) ; + this.resolvedType = type ; + } + + public TypeReference copyDims(int dim){ + //return a type reference copy of me with some dimensions + //warning : the new type ref has a null binding + + return new ArrayTypeReference(token,null,dim,(((long)sourceStart)<<32)+sourceEnd) ; + } + + public TypeBinding getTypeBinding(Scope scope) { + if (this.resolvedType != null) + return this.resolvedType; + return scope.getType(token); + } + + public char [][] getTypeName() { + return new char[][] { token }; + } + + public StringBuffer printExpression(int indent, StringBuffer output){ + + return output.append(token); + } + + public TypeBinding resolveTypeEnclosing(BlockScope scope, ReferenceBinding enclosingType) { + + ReferenceBinding memberTb = scope.getMemberType(token, enclosingType); + if (!memberTb.isValidBinding()) { + scope.problemReporter().invalidEnclosingType(this, memberTb, enclosingType); + return null; + } + if (isTypeUseDeprecated(memberTb, scope)) + scope.problemReporter().deprecatedType(memberTb, this); + return this.resolvedType = memberTb; + } + + public void traverse(ASTVisitor visitor, BlockScope scope) { + visitor.visit(this, scope); + visitor.endVisit(this, scope); + } + + public void traverse(ASTVisitor visitor, ClassScope scope) { + visitor.visit(this, scope); + visitor.endVisit(this, scope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/Statement.java b/src/java/org/eclipse/jdt/internal/compiler/ast/Statement.java new file mode 100644 index 0000000..2e240f7 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/Statement.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public abstract class Statement extends ASTNode { + + public abstract FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo); + + /** + * INTERNAL USE ONLY. + * This is used to redirect inter-statements jumps. + */ + public void branchChainTo(Label label) { + // do nothing by default + } + + // Report an error if necessary + public boolean complainIfUnreachable(FlowInfo flowInfo, BlockScope scope, boolean didAlreadyComplain) { + + if ((flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0) { + this.bits &= ~ASTNode.IsReachableMASK; + boolean reported = flowInfo == FlowInfo.DEAD_END; + if (!didAlreadyComplain && reported) { + scope.problemReporter().unreachableCode(this); + } + return reported; // keep going for fake reachable + } + return false; + } + + public abstract void generateCode(BlockScope currentScope, CodeStream codeStream); + + public boolean isEmptyBlock() { + return false; + } + + public boolean isValidJavaStatement() { + //the use of this method should be avoid in most cases + //and is here mostly for documentation purpose..... + //while the parser is responsable for creating + //welled formed expression statement, which results + //in the fact that java-non-semantic-expression-used-as-statement + //should not be parsable...thus not being built. + //It sounds like the java grammar as help the compiler job in removing + //-by construction- some statement that would have no effect.... + //(for example all expression that may do side-effects are valid statement + // -this is an appromative idea.....-) + + return true; + } + + public StringBuffer print(int indent, StringBuffer output) { + return printStatement(indent, output); + } + public abstract StringBuffer printStatement(int indent, StringBuffer output); + + public abstract void resolve(BlockScope scope); + + public Constant resolveCase(BlockScope scope, TypeBinding testType, SwitchStatement switchStatement) { + // statement within a switch that are not case are treated as normal statement.... + + resolve(scope); + return null; + } + +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/StringLiteral.java b/src/java/org/eclipse/jdt/internal/compiler/ast/StringLiteral.java new file mode 100644 index 0000000..833b5d5 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/StringLiteral.java @@ -0,0 +1,120 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.codegen.CodeStream; +import org.eclipse.jdt.internal.compiler.impl.Constant; +import org.eclipse.jdt.internal.compiler.lookup.BlockScope; +import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; + +public class StringLiteral extends Literal { + + char[] source; + + public StringLiteral(char[] token, int s, int e) { + + this(s,e); + source = token; + } + + public StringLiteral(int s, int e) { + + super(s,e); + } + + public void computeConstant() { + + constant = Constant.fromValue(String.valueOf(source)); + } + + public ExtendedStringLiteral extendWith(CharLiteral lit){ + + //add the lit source to mine, just as if it was mine + return new ExtendedStringLiteral(this,lit); + } + + public ExtendedStringLiteral extendWith(StringLiteral lit){ + + //add the lit source to mine, just as if it was mine + return new ExtendedStringLiteral(this,lit); + } + + /** + * Add the lit source to mine, just as if it was mine + */ + public StringLiteralConcatenation extendsWith(StringLiteral lit) { + return new StringLiteralConcatenation(this, lit); + } + /** + * Code generation for string literal + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { + + int pc = codeStream.position; + if (valueRequired) + codeStream.ldc(constant.stringValue()); + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public TypeBinding literalType(BlockScope scope) { + + return scope.getJavaLangString(); + } + + public StringBuffer printExpression(int indent, StringBuffer output) { + + // handle some special char..... + output.append('\"'); + for (int i = 0; i < source.length; i++) { + switch (source[i]) { + case '\b' : + output.append("\\b"); //$NON-NLS-1$ + break; + case '\t' : + output.append("\\t"); //$NON-NLS-1$ + break; + case '\n' : + output.append("\\n"); //$NON-NLS-1$ + break; + case '\f' : + output.append("\\f"); //$NON-NLS-1$ + break; + case '\r' : + output.append("\\r"); //$NON-NLS-1$ + break; + case '\"' : + output.append("\\\""); //$NON-NLS-1$ + break; + case '\'' : + output.append("\\'"); //$NON-NLS-1$ + break; + case '\\' : //take care not to display the escape as a potential real char + output.append("\\\\"); //$NON-NLS-1$ + break; + default : + output.append(source[i]); + } + } + output.append('\"'); + return output; + } + + public char[] source() { + + return source; + } + + public void traverse(ASTVisitor visitor, BlockScope scope) { + visitor.visit(this, scope); + visitor.endVisit(this, scope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/StringLiteralConcatenation.java b/src/java/org/eclipse/jdt/internal/compiler/ast/StringLiteralConcatenation.java new file mode 100644 index 0000000..77ee9cc --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/StringLiteralConcatenation.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.lookup.BlockScope; + +/** + * Flatten string literal + */ +public class StringLiteralConcatenation extends StringLiteral { + private static final int INITIAL_SIZE = 5; + public StringLiteral[] literals; + public int counter; + /** + * Build a two-strings literal + * */ + public StringLiteralConcatenation(StringLiteral str1, StringLiteral str2) { + super(str1.sourceStart, str1.sourceEnd); + this.source = str1.source; + this.literals = new StringLiteral[INITIAL_SIZE]; + this.counter = 0; + this.literals[this.counter++] = str1; + extendsWith(str2); + } + + /** + * Add the lit source to mine, just as if it was mine + */ + public StringLiteralConcatenation extendsWith(StringLiteral lit) { + this.sourceEnd = lit.sourceEnd; + final int literalsLength = this.literals.length; + if (this.counter == literalsLength) { + // resize + System.arraycopy(this.literals, 0, this.literals = new StringLiteral[literalsLength + INITIAL_SIZE], 0, literalsLength); + } + //uddate the source + int length = source.length; + System.arraycopy( + source, + 0, + source = new char[length + lit.source.length], + 0, + length); + System.arraycopy(lit.source, 0, source, length, lit.source.length); + this.literals[this.counter++] = lit; + return this; + } + + public StringBuffer printExpression(int indent, StringBuffer output) { + output.append("StringLiteralConcatenation{"); //$NON-NLS-1$ + for (int i = 0, max = this.counter; i < max; i++) { + this.literals[i].printExpression(indent, output); + output.append("+\n");//$NON-NLS-1$ + } + return output.append('}'); + } + + public char[] source() { + return source; + } + + public void traverse(ASTVisitor visitor, BlockScope scope) { + if (visitor.visit(this, scope)) { + for (int i = 0, max = this.counter; i < max; i++) { + this.literals[i].traverse(visitor, scope); + } + } + visitor.endVisit(this, scope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/SubRoutineStatement.java b/src/java/org/eclipse/jdt/internal/compiler/ast/SubRoutineStatement.java new file mode 100644 index 0000000..59b697b --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/SubRoutineStatement.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.codegen.CodeStream; +import org.eclipse.jdt.internal.compiler.codegen.ExceptionLabel; +import org.eclipse.jdt.internal.compiler.lookup.BlockScope; + +/** + * Extra behavior for statements which are generating subroutines + */ +public abstract class SubRoutineStatement extends Statement { + + public static final ExceptionLabel[] NO_EXCEPTION_HANDLER = new ExceptionLabel[0]; + ExceptionLabel[] anyExceptionLabels = NO_EXCEPTION_HANDLER; + int anyExceptionLabelsCount = 0; + + public abstract boolean isSubRoutineEscaping(); + + public abstract void generateSubRoutineInvocation(BlockScope currentScope, CodeStream codeStream); + + public ExceptionLabel enterAnyExceptionHandler(CodeStream codeStream) { + + int length; + if ((length = this.anyExceptionLabelsCount) == this.anyExceptionLabels.length) { + System.arraycopy(this.anyExceptionLabels, 0 , this.anyExceptionLabels=new ExceptionLabel[length*2 + 1], 0, length); + } + ExceptionLabel exceptionLabel = new ExceptionLabel(codeStream, null); + this.anyExceptionLabels[this.anyExceptionLabelsCount++] = exceptionLabel; + return exceptionLabel; + } + + public void exitAnyExceptionHandler() { + if (this.anyExceptionLabelsCount == 0) return; + ExceptionLabel currentLabel = this.anyExceptionLabels[this.anyExceptionLabelsCount-1]; + if (currentLabel.start == currentLabel.codeStream.position) { + // discard empty exception handler + this.anyExceptionLabels[--this.anyExceptionLabelsCount] = null; + } + currentLabel.placeEnd(); + } + + public void placeAllAnyExceptionHandlers() { + + for (int i = 0; i < this.anyExceptionLabelsCount; i++) { + this.anyExceptionLabels[i].place(); + } + } + + public static void reenterExceptionHandlers(SubRoutineStatement[] subroutines, int max, CodeStream codeStream) { + if (subroutines == null) return; + if (max < 0) max = subroutines.length; + for (int i = 0; i < max; i++) { + subroutines[i].enterAnyExceptionHandler(codeStream); + } + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/SuperReference.java b/src/java/org/eclipse/jdt/internal/compiler/ast/SuperReference.java new file mode 100644 index 0000000..a877d12 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/SuperReference.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.lookup.BlockScope; +import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding; +import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; + +public class SuperReference extends ThisReference { + + public SuperReference(int sourceStart, int sourceEnd) { + + super(sourceStart, sourceEnd); + } + + public static ExplicitConstructorCall implicitSuperConstructorCall() { + + return new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper); + } + + public boolean isImplicitThis() { + + return false; + } + + public boolean isSuper() { + + return true; + } + + public boolean isThis() { + + return false ; + } + + public StringBuffer printExpression(int indent, StringBuffer output){ + + return output.append("super"); //$NON-NLS-1$ + + } + + public TypeBinding resolveType(BlockScope scope) { + + constant = NotAConstant; + if (!checkAccess(scope.methodScope())) + return null; + SourceTypeBinding enclosingTb = scope.enclosingSourceType(); + if (enclosingTb.id == T_Object) { + scope.problemReporter().cannotUseSuperInJavaLangObject(this); + return null; + } + return this.resolvedType = enclosingTb.superclass; + } + + public void traverse(ASTVisitor visitor, BlockScope blockScope) { + visitor.visit(this, blockScope); + visitor.endVisit(this, blockScope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java b/src/java/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java new file mode 100644 index 0000000..65cddb1 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java @@ -0,0 +1,326 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class SwitchStatement extends Statement { + + public Expression expression; + public Statement[] statements; + public BlockScope scope; + public int explicitDeclarations; + public Label breakLabel; + public CaseStatement[] cases; + public CaseStatement defaultCase; + public int caseCount = 0; + public int blockStart; + + // for local variables table attributes + int preSwitchInitStateIndex = -1; + int mergedInitStateIndex = -1; + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + try { + flowInfo = expression.analyseCode(currentScope, flowContext, flowInfo); + SwitchFlowContext switchContext = + new SwitchFlowContext(flowContext, this, (breakLabel = new Label())); + + // analyse the block by considering specially the case/default statements (need to bind them + // to the entry point) + FlowInfo caseInits = FlowInfo.DEAD_END; + // in case of statements before the first case + preSwitchInitStateIndex = + currentScope.methodScope().recordInitializationStates(flowInfo); + int caseIndex = 0; + if (statements != null) { + boolean didAlreadyComplain = false; + for (int i = 0, max = statements.length; i < max; i++) { + Statement statement = statements[i]; + if ((caseIndex < caseCount) && (statement == cases[caseIndex])) { // statement is a case + this.scope.switchCase = cases[caseIndex]; // record entering in a switch case block + caseIndex++; + caseInits = caseInits.mergedWith(flowInfo.copy().unconditionalInits()); + didAlreadyComplain = false; // reset complaint + } else if (statement == defaultCase) { // statement is the default case + this.scope.switchCase = defaultCase; // record entering in a switch case block + caseInits = caseInits.mergedWith(flowInfo.copy().unconditionalInits()); + didAlreadyComplain = false; // reset complaint + } + if (!statement.complainIfUnreachable(caseInits, scope, didAlreadyComplain)) { + caseInits = statement.analyseCode(scope, switchContext, caseInits); + } else { + didAlreadyComplain = true; + } + } + } + + // if no default case, then record it may jump over the block directly to the end + if (defaultCase == null) { + // only retain the potential initializations + flowInfo.addPotentialInitializationsFrom( + caseInits.mergedWith(switchContext.initsOnBreak)); + mergedInitStateIndex = + currentScope.methodScope().recordInitializationStates(flowInfo); + return flowInfo; + } + + // merge all branches inits + FlowInfo mergedInfo = caseInits.mergedWith(switchContext.initsOnBreak); + mergedInitStateIndex = + currentScope.methodScope().recordInitializationStates(mergedInfo); + return mergedInfo; + } finally { + if (this.scope != null) this.scope.switchCase = null; // no longer inside switch case block + } + } + + /** + * Switch code generation + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + + try { + int[] sortedIndexes = new int[caseCount]; + int[] localKeysCopy; + if ((bits & IsReachableMASK) == 0) { + return; + } + int pc = codeStream.position; + + // prepare the labels and constants + breakLabel.initialize(codeStream); + CaseLabel[] caseLabels = new CaseLabel[caseCount]; + int[] constants = new int[caseCount]; + boolean needSwitch = caseCount != 0; + for (int i = 0; i < caseCount; i++) { + constants[i] = cases[i].constantExpression.constant.intValue(); + cases[i].targetLabel = (caseLabels[i] = new CaseLabel(codeStream)); + } + + // we sort the keys to be able to generate the code for tableswitch or lookupswitch + for (int i = 0; i < caseCount; i++) { + sortedIndexes[i] = i; + } + System.arraycopy( + constants, + 0, + (localKeysCopy = new int[caseCount]), + 0, + caseCount); + CodeStream.sort(localKeysCopy, 0, caseCount - 1, sortedIndexes); + CaseLabel defaultLabel = new CaseLabel(codeStream); + if (defaultCase != null) { + defaultCase.targetLabel = defaultLabel; + } + // generate expression testes + expression.generateCode(currentScope, codeStream, needSwitch); + + // generate the appropriate switch table/lookup bytecode + if (needSwitch) { + int max = localKeysCopy[caseCount - 1]; + int min = localKeysCopy[0]; + if ((long) (caseCount * 2.5) > ((long) max - (long) min)) { + + // work-around 1.3 VM bug, if max>0x7FFF0000, must use lookup bytecode + // see http://dev.eclipse.org/bugs/show_bug.cgi?id=21557 + if (max > 0x7FFF0000 && currentScope.environment().options.complianceLevel < ClassFileConstants.JDK1_4) { + codeStream.lookupswitch(defaultLabel, constants, sortedIndexes, caseLabels); + + } else { + codeStream.tableswitch( + defaultLabel, + min, + max, + constants, + sortedIndexes, + caseLabels); + } + } else { + codeStream.lookupswitch(defaultLabel, constants, sortedIndexes, caseLabels); + } + codeStream.updateLastRecordedEndPC(codeStream.position); + } + + // generate the switch block statements + int caseIndex = 0; + if (statements != null) { + for (int i = 0, maxCases = statements.length; i < maxCases; i++) { + Statement statement = statements[i]; + if ((caseIndex < caseCount) && (statement == cases[caseIndex])) { // statements[i] is a case + this.scope.switchCase = cases[caseIndex]; // record entering in a switch case block + if (preSwitchInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + preSwitchInitStateIndex); + } + caseIndex++; + } else { + if (statement == defaultCase) { // statements[i] is a case or a default case + this.scope.switchCase = defaultCase; // record entering in a switch case block + if (preSwitchInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + preSwitchInitStateIndex); + } + } + } + statement.generateCode(scope, codeStream); + } + } + // place the trailing labels (for break and default case) + breakLabel.place(); + if (defaultCase == null) { + defaultLabel.place(); + } + // May loose some local variable initializations : affecting the local variable attributes + if (mergedInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + mergedInitStateIndex); + codeStream.addDefinitelyAssignedVariables(currentScope, mergedInitStateIndex); + } + if (scope != currentScope) { + codeStream.exitUserScope(scope); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } finally { + if (this.scope != null) this.scope.switchCase = null; // no longer inside switch case block + } + } + + public StringBuffer printStatement(int indent, StringBuffer output) { + + printIndent(indent, output).append("switch ("); //$NON-NLS-1$ + expression.printExpression(0, output).append(") {"); //$NON-NLS-1$ + if (statements != null) { + for (int i = 0; i < statements.length; i++) { + output.append('\n'); + if (statements[i] instanceof CaseStatement) { + statements[i].printStatement(indent, output); + } else { + statements[i].printStatement(indent+2, output); + } + } + } + output.append("\n"); //$NON-NLS-1$ + return printIndent(indent, output).append('}'); + } + + public void resolve(BlockScope upperScope) { + + try { + TypeBinding testType = expression.resolveType(upperScope); + if (testType == null) + return; + expression.implicitWidening(testType, testType); + if (!(expression.isConstantValueOfTypeAssignableToType(testType, IntBinding))) { + if (!testType.isCompatibleWith(IntBinding)) { + upperScope.problemReporter().incorrectSwitchType(expression, testType); + return; + } + } + if (statements != null) { + scope = explicitDeclarations == 0 ? upperScope : new BlockScope(upperScope); + int length; + // collection of cases is too big but we will only iterate until caseCount + cases = new CaseStatement[length = statements.length]; + int[] casesValues = new int[length]; + CaseStatement[] duplicateCaseStatements = null; + int duplicateCaseStatementsCounter = 0; + int counter = 0; + for (int i = 0; i < length; i++) { + Constant constant; + final Statement statement = statements[i]; + if ((constant = statement.resolveCase(scope, testType, this)) != null) { + //----check for duplicate case statement------------ + if (constant != NotAConstant) { + int key = constant.intValue(); + for (int j = 0; j < counter; j++) { + if (casesValues[j] == key) { + final CaseStatement currentCaseStatement = (CaseStatement) statement; + if (duplicateCaseStatements == null) { + scope.problemReporter().duplicateCase(cases[j]); + scope.problemReporter().duplicateCase(currentCaseStatement); + duplicateCaseStatements = new CaseStatement[length]; + duplicateCaseStatements[duplicateCaseStatementsCounter++] = cases[j]; + duplicateCaseStatements[duplicateCaseStatementsCounter++] = currentCaseStatement; + } else { + boolean found = false; + searchReportedDuplicate: for (int k = 2; k < duplicateCaseStatementsCounter; k++) { + if (duplicateCaseStatements[k] == statement) { + found = true; + break searchReportedDuplicate; + } + } + if (!found) { + scope.problemReporter().duplicateCase(currentCaseStatement); + duplicateCaseStatements[duplicateCaseStatementsCounter++] = currentCaseStatement; + } + } + } + } + casesValues[counter++] = key; + } + } + } + } else { + if ((this.bits & UndocumentedEmptyBlockMASK) != 0) { + upperScope.problemReporter().undocumentedEmptyBlock(this.blockStart, this.sourceEnd); + } + } + } finally { + if (this.scope != null) this.scope.switchCase = null; // no longer inside switch case block + } + } + + public void traverse( + ASTVisitor visitor, + BlockScope blockScope) { + + if (visitor.visit(this, blockScope)) { + expression.traverse(visitor, scope); + if (statements != null) { + int statementsLength = statements.length; + for (int i = 0; i < statementsLength; i++) + statements[i].traverse(visitor, scope); + } + } + visitor.endVisit(this, blockScope); + } + + /** + * Dispatch the call on its last statement. + */ + public void branchChainTo(Label label) { + + // in order to improve debug attributes for stepping (11431) + // we want to inline the jumps to #breakLabel which already got + // generated (if any), and have them directly branch to a better + // location (the argument label). + // we know at this point that the breakLabel already got placed + if (this.breakLabel.hasForwardReferences()) { + label.appendForwardReferencesFrom(this.breakLabel); + } + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java b/src/java/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java new file mode 100644 index 0000000..2a45c54 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java @@ -0,0 +1,190 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class SynchronizedStatement extends SubRoutineStatement { + + public Expression expression; + public Block block; + public BlockScope scope; + boolean blockExit; + public LocalVariableBinding synchroVariable; + static final char[] SecretLocalDeclarationName = " syncValue".toCharArray(); //$NON-NLS-1$ + + public SynchronizedStatement( + Expression expression, + Block statement, + int s, + int e) { + + this.expression = expression; + this.block = statement; + sourceEnd = e; + sourceStart = s; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + // mark the synthetic variable as being used + synchroVariable.useFlag = LocalVariableBinding.USED; + + // simple propagation to subnodes + flowInfo = + block.analyseCode( + scope, + new InsideSubRoutineFlowContext(flowContext, this), + expression.analyseCode(scope, flowContext, flowInfo)); + + // optimizing code gen + this.blockExit = !flowInfo.isReachable(); + + return flowInfo; + } + + public boolean isSubRoutineEscaping() { + + return false; + } + + /** + * Synchronized statement code generation + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + + if ((bits & IsReachableMASK) == 0) { + return; + } + // in case the labels needs to be reinitialized + // when the code generation is restarted in wide mode + if (this.anyExceptionLabelsCount > 0) { + this.anyExceptionLabels = NO_EXCEPTION_HANDLER; + this.anyExceptionLabelsCount = 0; + } + int pc = codeStream.position; + + // generate the synchronization expression + expression.generateCode(scope, codeStream, true); + if (block.isEmptyBlock()) { + if ((synchroVariable.type == LongBinding) + || (synchroVariable.type == DoubleBinding)) { + codeStream.dup2(); + } else { + codeStream.dup(); + } + // only take the lock + codeStream.monitorenter(); + codeStream.monitorexit(); + } else { + // enter the monitor + codeStream.store(synchroVariable, true); + codeStream.monitorenter(); + + // generate the body of the synchronized block + this.enterAnyExceptionHandler(codeStream); + block.generateCode(scope, codeStream); + Label endLabel = new Label(codeStream); + if (!blockExit) { + codeStream.load(synchroVariable); + codeStream.monitorexit(); + codeStream.goto_(endLabel); + } + // generate the body of the exception handler + this.exitAnyExceptionHandler(); + this.placeAllAnyExceptionHandlers(); + codeStream.incrStackSize(1); + codeStream.load(synchroVariable); + codeStream.monitorexit(); + codeStream.athrow(); + if (!blockExit) { + endLabel.place(); + } + } + if (scope != currentScope) { + codeStream.exitUserScope(scope); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.ast.SubRoutineStatement#generateSubRoutineInvocation(org.eclipse.jdt.internal.compiler.lookup.BlockScope, org.eclipse.jdt.internal.compiler.codegen.CodeStream) + */ + public void generateSubRoutineInvocation( + BlockScope currentScope, + CodeStream codeStream) { + + codeStream.load(this.synchroVariable); + codeStream.monitorexit(); + } + + public void resolve(BlockScope upperScope) { + + // special scope for secret locals optimization. + scope = new BlockScope(upperScope); + TypeBinding type = expression.resolveType(scope); + if (type == null) + return; + switch (type.id) { + case (T_boolean) : + case (T_char) : + case (T_float) : + case (T_double) : + case (T_byte) : + case (T_short) : + case (T_int) : + case (T_long) : + scope.problemReporter().invalidTypeToSynchronize(expression, type); + break; + case (T_void) : + scope.problemReporter().illegalVoidExpression(expression); + break; + case (T_null) : + scope.problemReporter().invalidNullToSynchronize(expression); + break; + } + //continue even on errors in order to have the TC done into the statements + synchroVariable = new LocalVariableBinding(SecretLocalDeclarationName, type, AccDefault, false); + scope.addLocalVariable(synchroVariable); + synchroVariable.constant = NotAConstant; // not inlinable + expression.implicitWidening(type, type); + block.resolveUsing(scope); + } + + public StringBuffer printStatement(int indent, StringBuffer output) { + + printIndent(indent, output); + output.append("synchronized ("); //$NON-NLS-1$ + expression.printExpression(0, output).append(')'); + output.append('\n'); + return block.printStatement(indent + 1, output); + } + + public void traverse( + ASTVisitor visitor, + BlockScope blockScope) { + + if (visitor.visit(this, blockScope)) { + expression.traverse(visitor, scope); + block.traverse(visitor, scope); + } + visitor.endVisit(this, blockScope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/ThisReference.java b/src/java/org/eclipse/jdt/internal/compiler/ast/ThisReference.java new file mode 100644 index 0000000..78ccdfa --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/ThisReference.java @@ -0,0 +1,120 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.FlowContext; +import org.eclipse.jdt.internal.compiler.flow.FlowInfo; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class ThisReference extends Reference { + + public static ThisReference implicitThis(){ + + ThisReference implicitThis = new ThisReference(0, 0); + implicitThis.bits |= IsImplicitThisMask; + return implicitThis; + } + + public ThisReference(int sourceStart, int sourceEnd) { + + this.sourceStart = sourceStart; + this.sourceEnd = sourceEnd; + } + + /* + * @see Reference#analyseAssignment(...) + */ + public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound) { + + return flowInfo; // this cannot be assigned + } + + public boolean checkAccess(MethodScope methodScope) { + + // this/super cannot be used in constructor call + if (methodScope.isConstructorCall) { + methodScope.problemReporter().fieldsOrThisBeforeConstructorInvocation(this); + return false; + } + + // static may not refer to this/super + if (methodScope.isStatic) { + methodScope.problemReporter().errorThisSuperInStatic(this); + return false; + } + return true; + } + + /* + * @see Reference#generateAssignment(...) + */ + public void generateAssignment(BlockScope currentScope, CodeStream codeStream, Assignment assignment, boolean valueRequired) { + + // this cannot be assigned + } + + public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { + + int pc = codeStream.position; + if (valueRequired) + codeStream.aload_0(); + if ((this.bits & IsImplicitThisMask) == 0) codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + /* + * @see Reference#generateCompoundAssignment(...) + */ + public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) { + + // this cannot be assigned + } + + /* + * @see org.eclipse.jdt.internal.compiler.ast.Reference#generatePostIncrement() + */ + public void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired) { + + // this cannot be assigned + } + + public boolean isImplicitThis() { + + return (this.bits & IsImplicitThisMask) != 0; + } + + public boolean isThis() { + + return true ; + } + + public StringBuffer printExpression(int indent, StringBuffer output){ + + if (this.isImplicitThis()) return output; + return output.append("this"); //$NON-NLS-1$ + } + + public TypeBinding resolveType(BlockScope scope) { + + constant = NotAConstant; + if (!this.isImplicitThis() &&!checkAccess(scope.methodScope())) { + return null; + } + return this.resolvedType = scope.enclosingSourceType(); + } + + public void traverse(ASTVisitor visitor, BlockScope blockScope) { + + visitor.visit(this, blockScope); + visitor.endVisit(this, blockScope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/ThrowStatement.java b/src/java/org/eclipse/jdt/internal/compiler/ast/ThrowStatement.java new file mode 100644 index 0000000..dac8920 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/ThrowStatement.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.codegen.CodeStream; +import org.eclipse.jdt.internal.compiler.flow.FlowContext; +import org.eclipse.jdt.internal.compiler.flow.FlowInfo; +import org.eclipse.jdt.internal.compiler.lookup.BlockScope; +import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; + +public class ThrowStatement extends Statement { + public Expression exception; + public TypeBinding exceptionType; + + public ThrowStatement(Expression exception, int startPosition) { + this.exception = exception; + this.sourceStart = startPosition; + this.sourceEnd = exception.sourceEnd; + } + + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + + exception.analyseCode(currentScope, flowContext, flowInfo); + // need to check that exception thrown is actually caught somewhere + flowContext.checkExceptionHandlers(exceptionType, this, flowInfo, currentScope); + return FlowInfo.DEAD_END; + } + + /** + * Throw code generation + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + + if ((bits & IsReachableMASK) == 0) + return; + int pc = codeStream.position; + exception.generateCode(currentScope, codeStream, true); + codeStream.athrow(); + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public StringBuffer printStatement(int indent, StringBuffer output) { + + printIndent(indent, output).append("throw "); //$NON-NLS-1$ + exception.printExpression(0, output); + return output.append(';'); + } + + public void resolve(BlockScope scope) { + + exceptionType = exception.resolveTypeExpecting(scope, scope.getJavaLangThrowable()); + + if (exceptionType == NullBinding + && scope.environment().options.complianceLevel <= ClassFileConstants.JDK1_3){ + // if compliant with 1.4, this problem will not be reported + scope.problemReporter().cannotThrowNull(this); + } + exception.implicitWidening(exceptionType, exceptionType); + } + + public void traverse(ASTVisitor visitor, BlockScope blockScope) { + if (visitor.visit(this, blockScope)) + exception.traverse(visitor, blockScope); + visitor.endVisit(this, blockScope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/TrueLiteral.java b/src/java/org/eclipse/jdt/internal/compiler/ast/TrueLiteral.java new file mode 100644 index 0000000..14dc78f --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/TrueLiteral.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.codegen.CodeStream; +import org.eclipse.jdt.internal.compiler.codegen.Label; +import org.eclipse.jdt.internal.compiler.impl.Constant; +import org.eclipse.jdt.internal.compiler.lookup.BlockScope; +import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; + +public class TrueLiteral extends MagicLiteral { + static final char[] source = {'t' , 'r' , 'u' , 'e'}; +public TrueLiteral(int s , int e) { + super(s,e); +} +public void computeConstant() { + + constant = Constant.fromValue(true);} +/** + * Code generation for the true literal + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ +public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { + int pc = codeStream.position; + if (valueRequired) + codeStream.iconst_1(); + codeStream.recordPositionsFrom(pc, this.sourceStart); +} +public void generateOptimizedBoolean(BlockScope currentScope, CodeStream codeStream, Label trueLabel, Label falseLabel, boolean valueRequired) { + + // trueLabel being not nil means that we will not fall through into the TRUE case + + int pc = codeStream.position; + // constant == true + if (valueRequired) { + if (falseLabel == null) { + // implicit falling through the FALSE case + if (trueLabel != null) { + codeStream.goto_(trueLabel); + } + } + } + codeStream.recordPositionsFrom(pc, this.sourceStart); +} +public TypeBinding literalType(BlockScope scope) { + return BooleanBinding; +} +/** + * + */ +public char[] source() { + return source; +} +public void traverse(ASTVisitor visitor, BlockScope scope) { + visitor.visit(this, scope); + visitor.endVisit(this, scope); +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/TryStatement.java b/src/java/org/eclipse/jdt/internal/compiler/ast/TryStatement.java new file mode 100644 index 0000000..bda4130 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/TryStatement.java @@ -0,0 +1,572 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class TryStatement extends SubRoutineStatement { + + public Block tryBlock; + public Block[] catchBlocks; + public Argument[] catchArguments; + public Block finallyBlock; + BlockScope scope; + + private boolean isSubRoutineEscaping = false; + public UnconditionalFlowInfo subRoutineInits; + + // should rename into subRoutineComplete to be set to false by default + + ReferenceBinding[] caughtExceptionTypes; + boolean tryBlockExit; + boolean[] catchExits; + public int[] preserveExceptionHandler; + + Label subRoutineStartLabel; + public LocalVariableBinding anyExceptionVariable, + returnAddressVariable, + secretReturnValue; + + public final static char[] SecretReturnName = " returnAddress".toCharArray(); //$NON-NLS-1$ + public final static char[] SecretAnyHandlerName = " anyExceptionHandler".toCharArray(); //$NON-NLS-1$ + public static final char[] SecretLocalDeclarationName = " returnValue".toCharArray(); //$NON-NLS-1$ + + // for local variables table attributes + int preTryInitStateIndex = -1; + int mergedInitStateIndex = -1; + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + // Consider the try block and catch block so as to compute the intersection of initializations and + // the minimum exit relative depth amongst all of them. Then consider the subroutine, and append its + // initialization to the try/catch ones, if the subroutine completes normally. If the subroutine does not + // complete, then only keep this result for the rest of the analysis + + // process the finally block (subroutine) - create a context for the subroutine + + preTryInitStateIndex = + currentScope.methodScope().recordInitializationStates(flowInfo); + + if (anyExceptionVariable != null) { + anyExceptionVariable.useFlag = LocalVariableBinding.USED; + } + if (returnAddressVariable != null) { // TODO (philippe) if subroutine is escaping, unused + returnAddressVariable.useFlag = LocalVariableBinding.USED; + } + InsideSubRoutineFlowContext insideSubContext; + FinallyFlowContext finallyContext; + UnconditionalFlowInfo subInfo; + if (subRoutineStartLabel == null) { + // no finally block + insideSubContext = null; + finallyContext = null; + subInfo = null; + } else { + // analyse finally block first + insideSubContext = new InsideSubRoutineFlowContext(flowContext, this); + subInfo = + finallyBlock + .analyseCode( + currentScope, + finallyContext = new FinallyFlowContext(flowContext, finallyBlock), + flowInfo.copy()) + .unconditionalInits(); + if (subInfo == FlowInfo.DEAD_END) { + isSubRoutineEscaping = true; + scope.problemReporter().finallyMustCompleteNormally(finallyBlock); + } + this.subRoutineInits = subInfo; + } + // process the try block in a context handling the local exceptions. + ExceptionHandlingFlowContext handlingContext = + new ExceptionHandlingFlowContext( + insideSubContext == null ? flowContext : insideSubContext, + tryBlock, + caughtExceptionTypes, + scope, + flowInfo.unconditionalInits()); + + FlowInfo tryInfo; + if (tryBlock.isEmptyBlock()) { + tryInfo = flowInfo; + tryBlockExit = false; + } else { + tryInfo = tryBlock.analyseCode(currentScope, handlingContext, flowInfo.copy()); + tryBlockExit = !tryInfo.isReachable(); + } + + // check unreachable catch blocks + handlingContext.complainIfUnusedExceptionHandlers(scope, this); + + // process the catch blocks - computing the minimal exit depth amongst try/catch + if (catchArguments != null) { + int catchCount; + catchExits = new boolean[catchCount = catchBlocks.length]; + for (int i = 0; i < catchCount; i++) { + // keep track of the inits that could potentially have led to this exception handler (for final assignments diagnosis) + FlowInfo catchInfo = + flowInfo + .copy() + .unconditionalInits() + .addPotentialInitializationsFrom( + handlingContext.initsOnException(caughtExceptionTypes[i]).unconditionalInits()) + .addPotentialInitializationsFrom(tryInfo.unconditionalInits()) + .addPotentialInitializationsFrom(handlingContext.initsOnReturn); + + // catch var is always set + catchInfo.markAsDefinitelyAssigned(catchArguments[i].binding); + /* + "If we are about to consider an unchecked exception handler, potential inits may have occured inside + the try block that need to be detected , e.g. + try { x = 1; throwSomething();} catch(Exception e){ x = 2} " + "(uncheckedExceptionTypes notNil and: [uncheckedExceptionTypes at: index]) + ifTrue: [catchInits addPotentialInitializationsFrom: tryInits]." + */ + // TODO (philippe) should only tag as unreachable if the catchblock cannot be reached? + //??? if (!handlingContext.initsOnException(caughtExceptionTypes[i]).isReachable()){ + if (tryBlock.statements == null) { + catchInfo.setReachMode(FlowInfo.UNREACHABLE); + } + catchInfo = + catchBlocks[i].analyseCode( + currentScope, + insideSubContext == null ? flowContext : insideSubContext, + catchInfo); + catchExits[i] = !catchInfo.isReachable(); + tryInfo = tryInfo.mergedWith(catchInfo.unconditionalInits()); + } + } + if (subRoutineStartLabel == null) { + mergedInitStateIndex = + currentScope.methodScope().recordInitializationStates(tryInfo); + return tryInfo; + } + + + // we also need to check potential multiple assignments of final variables inside the finally block + // need to include potential inits from returns inside the try/catch parts - 1GK2AOF + finallyContext.complainOnRedundantFinalAssignments( + tryInfo.isReachable() + ? (tryInfo.addPotentialInitializationsFrom(insideSubContext.initsOnReturn)) + : insideSubContext.initsOnReturn, + currentScope); + if (subInfo == FlowInfo.DEAD_END) { + mergedInitStateIndex = + currentScope.methodScope().recordInitializationStates(subInfo); + return subInfo; + } else { + FlowInfo mergedInfo = tryInfo.addInitializationsFrom(subInfo); + mergedInitStateIndex = + currentScope.methodScope().recordInitializationStates(mergedInfo); + return mergedInfo; + } + } + + public boolean isSubRoutineEscaping() { + + return isSubRoutineEscaping; + } + + /** + * Try statement code generation with or without jsr bytecode use + * post 1.5 target level, cannot use jsr bytecode, must instead inline finally block + * returnAddress is only allocated if jsr is allowed + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + + if ((bits & IsReachableMASK) == 0) { + return; + } + // in case the labels needs to be reinitialized + // when the code generation is restarted in wide mode + if (this.anyExceptionLabelsCount > 0) { + this.anyExceptionLabels = NO_EXCEPTION_HANDLER; + this.anyExceptionLabelsCount = 0; + } + int pc = codeStream.position; + final int NO_FINALLY = 0; // no finally block + final int FINALLY_SUBROUTINE = 1; // finally is generated as a subroutine (using jsr/ret bytecodes) + final int FINALLY_DOES_NOT_COMPLETE = 2; // non returning finally is optimized with only one instance of finally block + final int FINALLY_MUST_BE_INLINED = 3; // finally block must be inlined since cannot use jsr/ret bytecodes >1.5 + int finallyMode; + if (subRoutineStartLabel == null) { + finallyMode = NO_FINALLY; + } else { + if (this.isSubRoutineEscaping) { + finallyMode = FINALLY_DOES_NOT_COMPLETE; + } else if (scope.environment().options.inlineJsrBytecode) { + finallyMode = FINALLY_MUST_BE_INLINED; + } else { + finallyMode = FINALLY_SUBROUTINE; + } + } + boolean requiresNaturalExit = false; + // preparing exception labels + int maxCatches; + ExceptionLabel[] exceptionLabels = + new ExceptionLabel[maxCatches = + catchArguments == null ? 0 : catchArguments.length]; + for (int i = 0; i < maxCatches; i++) { + exceptionLabels[i] = new ExceptionLabel(codeStream, catchArguments[i].binding.type); + } + if (subRoutineStartLabel != null) { + subRoutineStartLabel.initialize(codeStream); + this.enterAnyExceptionHandler(codeStream); + } + // generate the try block + tryBlock.generateCode(scope, codeStream); + boolean tryBlockHasSomeCode = codeStream.position != pc; + // flag telling if some bytecodes were issued inside the try block + + // place end positions of user-defined exception labels + if (tryBlockHasSomeCode) { + // natural exit may require subroutine invocation (if finally != null) + Label naturalExitLabel = new Label(codeStream); + if (!tryBlockExit) { + int position = codeStream.position; + switch(finallyMode) { + case FINALLY_SUBROUTINE : + case FINALLY_MUST_BE_INLINED : + requiresNaturalExit = true; + // fall through + case NO_FINALLY : + codeStream.goto_(naturalExitLabel); + break; + case FINALLY_DOES_NOT_COMPLETE : + codeStream.goto_(subRoutineStartLabel); + break; + } + codeStream.updateLastRecordedEndPC(position); + //goto is tagged as part of the try block + } + for (int i = 0; i < maxCatches; i++) { + exceptionLabels[i].placeEnd(); + } + /* generate sequence of handler, all starting by storing the TOS (exception + thrown) into their own catch variables, the one specified in the source + that must denote the handled exception. + */ + if (catchArguments == null) { + this.exitAnyExceptionHandler(); + } else { + for (int i = 0; i < maxCatches; i++) { + // May loose some local variable initializations : affecting the local variable attributes + if (preTryInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + preTryInitStateIndex); + } + exceptionLabels[i].place(); + codeStream.incrStackSize(1); + // optimizing the case where the exception variable is not actually used + LocalVariableBinding catchVar; + int varPC = codeStream.position; + if ((catchVar = catchArguments[i].binding).resolvedPosition != -1) { + codeStream.store(catchVar, false); + catchVar.recordInitializationStartPC(codeStream.position); + codeStream.addVisibleLocalVariable(catchVar); + } else { + codeStream.pop(); + } + codeStream.recordPositionsFrom(varPC, catchArguments[i].sourceStart); + // Keep track of the pcs at diverging point for computing the local attribute + // since not passing the catchScope, the block generation will exitUserScope(catchScope) + catchBlocks[i].generateCode(scope, codeStream); + + if (i == maxCatches - 1) { + this.exitAnyExceptionHandler(); + } + if (!catchExits[i]) { + switch(finallyMode) { + case FINALLY_SUBROUTINE : + case FINALLY_MUST_BE_INLINED : + requiresNaturalExit = true; + // fall through + case NO_FINALLY : + codeStream.goto_(naturalExitLabel); + break; + case FINALLY_DOES_NOT_COMPLETE : + codeStream.goto_(subRoutineStartLabel); + break; + } + } + } + } + // extra handler for trailing natural exit (will be fixed up later on when natural exit is generated below) + ExceptionLabel naturalExitExceptionHandler = + finallyMode == FINALLY_SUBROUTINE && requiresNaturalExit ? this.enterAnyExceptionHandler(codeStream) : null; + + // addition of a special handler so as to ensure that any uncaught exception (or exception thrown + // inside catch blocks) will run the finally block + int finallySequenceStartPC = codeStream.position; + if (subRoutineStartLabel != null) { + // the additional handler is doing: jsr finallyBlock and rethrow TOS-exception + this.placeAllAnyExceptionHandlers(); + + if (preTryInitStateIndex != -1) { + // reset initialization state, as for a normal catch block + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + preTryInitStateIndex); + } + + codeStream.incrStackSize(1); + switch(finallyMode) { + + case FINALLY_SUBROUTINE : + codeStream.store(anyExceptionVariable, false); + codeStream.jsr(subRoutineStartLabel); + codeStream.load(anyExceptionVariable); + codeStream.athrow(); + subRoutineStartLabel.place(); + codeStream.incrStackSize(1); + codeStream.store(returnAddressVariable, false); + codeStream.recordPositionsFrom(finallySequenceStartPC, finallyBlock.sourceStart); + finallyBlock.generateCode(scope, codeStream); + int position = codeStream.position; + codeStream.ret(returnAddressVariable.resolvedPosition); + codeStream.updateLastRecordedEndPC(position); + codeStream.recordPositionsFrom( + position, + finallyBlock.sourceEnd); + // the ret bytecode is part of the subroutine + break; + + case FINALLY_MUST_BE_INLINED : + codeStream.store(anyExceptionVariable, false); + this.finallyBlock.generateCode(currentScope, codeStream); + codeStream.load(anyExceptionVariable); + codeStream.athrow(); + subRoutineStartLabel.place(); + codeStream.recordPositionsFrom(finallySequenceStartPC, finallyBlock.sourceStart); + break; + + case FINALLY_DOES_NOT_COMPLETE : + codeStream.pop(); + subRoutineStartLabel.place(); + codeStream.recordPositionsFrom(finallySequenceStartPC, finallyBlock.sourceStart); + finallyBlock.generateCode(scope, codeStream); + break; + } + // will naturally fall into subsequent code after subroutine invocation + naturalExitLabel.place(); + if (requiresNaturalExit) { + switch(finallyMode) { + + case FINALLY_SUBROUTINE : + int position = codeStream.position; + // fix up natural exit handler + naturalExitExceptionHandler.placeStart(); + codeStream.jsr(subRoutineStartLabel); + naturalExitExceptionHandler.placeEnd(); + codeStream.recordPositionsFrom( + position, + finallyBlock.sourceStart); + break; + + case FINALLY_MUST_BE_INLINED : + // May loose some local variable initializations : affecting the local variable attributes + // needed since any exception handler got inlined subroutine + if (preTryInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + preTryInitStateIndex); + } + // entire sequence for finally is associated to finally block + finallyBlock.generateCode(scope, codeStream); + break; + + case FINALLY_DOES_NOT_COMPLETE : + break; + } + } + } else { + // no subroutine, simply position end label (natural exit == end) + naturalExitLabel.place(); + } + } else { + // try block had no effect, only generate the body of the finally block if any + if (subRoutineStartLabel != null) { + finallyBlock.generateCode(scope, codeStream); + } + } + // May loose some local variable initializations : affecting the local variable attributes + if (mergedInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + mergedInitStateIndex); + codeStream.addDefinitelyAssignedVariables(currentScope, mergedInitStateIndex); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.ast.SubRoutineStatement#generateSubRoutineInvocation(org.eclipse.jdt.internal.compiler.lookup.BlockScope, org.eclipse.jdt.internal.compiler.codegen.CodeStream) + */ + public void generateSubRoutineInvocation( + BlockScope currentScope, + CodeStream codeStream) { + + if (this.isSubRoutineEscaping) { + codeStream.goto_(this.subRoutineStartLabel); + } else { + if (currentScope.environment().options.inlineJsrBytecode) { + // cannot use jsr bytecode, then simply inline the subroutine + this.finallyBlock.generateCode(currentScope, codeStream); + } else { + // classic subroutine invocation, distinguish case of non-returning subroutine + codeStream.jsr(this.subRoutineStartLabel); + } + } + } + + public StringBuffer printStatement(int indent, StringBuffer output) { + printIndent(indent, output).append("try \n"); //$NON-NLS-1$ + tryBlock.printStatement(indent + 1, output); //$NON-NLS-1$ + + //catches + if (catchBlocks != null) + for (int i = 0; i < catchBlocks.length; i++) { + output.append('\n'); + printIndent(indent, output).append("catch ("); //$NON-NLS-1$ + catchArguments[i].print(0, output).append(") "); //$NON-NLS-1$ + catchBlocks[i].printStatement(indent + 1, output); + } + //finally + if (finallyBlock != null) { + output.append('\n'); + printIndent(indent, output).append("finally\n"); //$NON-NLS-1$ + finallyBlock.printStatement(indent + 1, output); + } + + return output; + } + + public void resolve(BlockScope upperScope) { + + // special scope for secret locals optimization. + this.scope = new BlockScope(upperScope); + + BlockScope tryScope = new BlockScope(scope); + BlockScope finallyScope = null; + + if (finallyBlock != null) { + if (finallyBlock.isEmptyBlock()) { + if ((finallyBlock.bits & UndocumentedEmptyBlockMASK) != 0) { + scope.problemReporter().undocumentedEmptyBlock(finallyBlock.sourceStart, finallyBlock.sourceEnd); + } + } else { + finallyScope = new BlockScope(scope, false); // don't add it yet to parent scope + + // provision for returning and forcing the finally block to run + MethodScope methodScope = scope.methodScope(); + + // the type does not matter as long as it is not a base type + if (!upperScope.environment().options.inlineJsrBytecode) { + this.returnAddressVariable = + new LocalVariableBinding(SecretReturnName, upperScope.getJavaLangObject(), AccDefault, false); + finallyScope.addLocalVariable(returnAddressVariable); + this.returnAddressVariable.constant = NotAConstant; // not inlinable + } + this.subRoutineStartLabel = new Label(); + + this.anyExceptionVariable = + new LocalVariableBinding(SecretAnyHandlerName, scope.getJavaLangThrowable(), AccDefault, false); + finallyScope.addLocalVariable(this.anyExceptionVariable); + this.anyExceptionVariable.constant = NotAConstant; // not inlinable + + if (!methodScope.isInsideInitializer()) { + MethodBinding methodBinding = + ((AbstractMethodDeclaration) methodScope.referenceContext).binding; + if (methodBinding != null) { + TypeBinding methodReturnType = methodBinding.returnType; + if (methodReturnType.id != T_void) { + this.secretReturnValue = + new LocalVariableBinding( + SecretLocalDeclarationName, + methodReturnType, + AccDefault, + false); + finallyScope.addLocalVariable(this.secretReturnValue); + this.secretReturnValue.constant = NotAConstant; // not inlinable + } + } + } + finallyBlock.resolveUsing(finallyScope); + // force the finally scope to have variable positions shifted after its try scope and catch ones + finallyScope.shiftScopes = new BlockScope[catchArguments == null ? 1 : catchArguments.length+1]; + finallyScope.shiftScopes[0] = tryScope; + } + } + this.tryBlock.resolveUsing(tryScope); + + // arguments type are checked against JavaLangThrowable in resolveForCatch(..) + if (this.catchBlocks != null) { + int length = this.catchArguments.length; + TypeBinding[] argumentTypes = new TypeBinding[length]; + for (int i = 0; i < length; i++) { + BlockScope catchScope = new BlockScope(scope); + if (finallyScope != null){ + finallyScope.shiftScopes[i+1] = catchScope; + } + // side effect on catchScope in resolveForCatch(..) + if ((argumentTypes[i] = catchArguments[i].resolveForCatch(catchScope)) == null) + return; + catchBlocks[i].resolveUsing(catchScope); + } + + // Verify that the catch clause are ordered in the right way: + // more specialized first. + this.caughtExceptionTypes = new ReferenceBinding[length]; + for (int i = 0; i < length; i++) { + caughtExceptionTypes[i] = (ReferenceBinding) argumentTypes[i]; + for (int j = 0; j < i; j++) { + if (caughtExceptionTypes[i].isCompatibleWith(argumentTypes[j])) { + scope.problemReporter().wrongSequenceOfExceptionTypesError(this, caughtExceptionTypes[i], i, argumentTypes[j]); + } + } + } + } else { + caughtExceptionTypes = new ReferenceBinding[0]; + } + + if (finallyScope != null){ + // add finallyScope as last subscope, so it can be shifted behind try/catch subscopes. + // the shifting is necessary to achieve no overlay in between the finally scope and its + // sibling in term of local variable positions. + this.scope.addSubscope(finallyScope); + } + } + + public void traverse( + ASTVisitor visitor, + BlockScope blockScope) { + + if (visitor.visit(this, blockScope)) { + tryBlock.traverse(visitor, scope); + if (catchArguments != null) { + for (int i = 0, max = catchBlocks.length; i < max; i++) { + catchArguments[i].traverse(visitor, scope); + catchBlocks[i].traverse(visitor, scope); + } + } + if (finallyBlock != null) + finallyBlock.traverse(visitor, scope); + } + visitor.endVisit(this, blockScope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java b/src/java/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java new file mode 100644 index 0000000..b6ba6f1 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java @@ -0,0 +1,1135 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.core.compiler.*; +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.*; +import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; +import org.eclipse.jdt.internal.compiler.parser.*; +import org.eclipse.jdt.internal.compiler.problem.*; + +public class TypeDeclaration + extends Statement + implements ProblemSeverities, ReferenceContext { + + public static final char[] ANONYMOUS_EMPTY_NAME = new char[] {}; + + public int modifiers = AccDefault; + public int modifiersSourceStart; + public char[] name; + public TypeReference superclass; + public TypeReference[] superInterfaces; + public FieldDeclaration[] fields; + public AbstractMethodDeclaration[] methods; + public TypeDeclaration[] memberTypes; + public SourceTypeBinding binding; + public ClassScope scope; + public MethodScope initializerScope; + public MethodScope staticInitializerScope; + public boolean ignoreFurtherInvestigation = false; + public int maxFieldCount; + public int declarationSourceStart; + public int declarationSourceEnd; + public int bodyStart; + public int bodyEnd; // doesn't include the trailing comment if any. + protected boolean hasBeenGenerated = false; + public CompilationResult compilationResult; + private MethodDeclaration[] missingAbstractMethods; + public Javadoc javadoc; + + public QualifiedAllocationExpression allocation; // for anonymous only + public TypeDeclaration enclosingType; // for member types only + + public TypeDeclaration(CompilationResult compilationResult){ + this.compilationResult = compilationResult; + } + + /* + * We cause the compilation task to abort to a given extent. + */ + public void abort(int abortLevel, IProblem problem) { + + switch (abortLevel) { + case AbortCompilation : + throw new AbortCompilation(this.compilationResult, problem); + case AbortCompilationUnit : + throw new AbortCompilationUnit(this.compilationResult, problem); + case AbortMethod : + throw new AbortMethod(this.compilationResult, problem); + default : + throw new AbortType(this.compilationResult, problem); + } + } + /** + * This method is responsible for adding a method declaration to the type method collections. + * Note that this implementation is inserting it in first place (as VAJ or javac), and that this + * impacts the behavior of the method ConstantPool.resetForClinit(int. int), in so far as + * the latter will have to reset the constant pool state accordingly (if it was added first, it does + * not need to preserve some of the method specific cached entries since this will be the first method). + * inserts the clinit method declaration in the first position. + * + * @see org.eclipse.jdt.internal.compiler.codegen.ConstantPool#resetForClinit(int, int) + */ + public final void addClinit() { + + //see comment on needClassInitMethod + if (needClassInitMethod()) { + int length; + AbstractMethodDeclaration[] methodDeclarations; + if ((methodDeclarations = this.methods) == null) { + length = 0; + methodDeclarations = new AbstractMethodDeclaration[1]; + } else { + length = methodDeclarations.length; + System.arraycopy( + methodDeclarations, + 0, + (methodDeclarations = new AbstractMethodDeclaration[length + 1]), + 1, + length); + } + Clinit clinit = new Clinit(this.compilationResult); + methodDeclarations[0] = clinit; + // clinit is added in first location, so as to minimize the use of ldcw (big consumer of constant inits) + clinit.declarationSourceStart = clinit.sourceStart = sourceStart; + clinit.declarationSourceEnd = clinit.sourceEnd = sourceEnd; + clinit.bodyEnd = sourceEnd; + this.methods = methodDeclarations; + } + } + + /* + * INTERNAL USE ONLY - Creates a fake method declaration for the corresponding binding. + * It is used to report errors for missing abstract methods. + */ + public MethodDeclaration addMissingAbstractMethodFor(MethodBinding methodBinding) { + TypeBinding[] argumentTypes = methodBinding.parameters; + int argumentsLength = argumentTypes.length; + //the constructor + MethodDeclaration methodDeclaration = new MethodDeclaration(this.compilationResult); + methodDeclaration.selector = methodBinding.selector; + methodDeclaration.sourceStart = sourceStart; + methodDeclaration.sourceEnd = sourceEnd; + methodDeclaration.modifiers = methodBinding.getAccessFlags() & ~AccAbstract; + + if (argumentsLength > 0) { + String baseName = "arg";//$NON-NLS-1$ + Argument[] arguments = (methodDeclaration.arguments = new Argument[argumentsLength]); + for (int i = argumentsLength; --i >= 0;) { + arguments[i] = new Argument((baseName + i).toCharArray(), 0L, null /*type ref*/, AccDefault); + } + } + + //adding the constructor in the methods list + if (this.missingAbstractMethods == null) { + this.missingAbstractMethods = new MethodDeclaration[] { methodDeclaration }; + } else { + MethodDeclaration[] newMethods; + System.arraycopy( + this.missingAbstractMethods, + 0, + newMethods = new MethodDeclaration[this.missingAbstractMethods.length + 1], + 1, + this.missingAbstractMethods.length); + newMethods[0] = methodDeclaration; + this.missingAbstractMethods = newMethods; + } + + //============BINDING UPDATE========================== + methodDeclaration.binding = new MethodBinding( + methodDeclaration.modifiers, //methodDeclaration + methodBinding.selector, + methodBinding.returnType, + argumentsLength == 0 ? NoParameters : argumentTypes, //arguments bindings + methodBinding.thrownExceptions, //exceptions + binding); //declaringClass + + methodDeclaration.scope = new MethodScope(scope, methodDeclaration, true); + methodDeclaration.bindArguments(); + +/* if (binding.methods == null) { + binding.methods = new MethodBinding[] { methodDeclaration.binding }; + } else { + MethodBinding[] newMethods; + System.arraycopy( + binding.methods, + 0, + newMethods = new MethodBinding[binding.methods.length + 1], + 1, + binding.methods.length); + newMethods[0] = methodDeclaration.binding; + binding.methods = newMethods; + }*/ + //=================================================== + + return methodDeclaration; + } + + /** + * Flow analysis for a local innertype + * + */ + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + if (ignoreFurtherInvestigation) + return flowInfo; + try { + if (flowInfo.isReachable()) { + bits |= IsReachableMASK; + LocalTypeBinding localType = (LocalTypeBinding) binding; + localType.setConstantPoolName(currentScope.compilationUnitScope().computeConstantPoolName(localType)); + } + manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo); + updateMaxFieldCount(); // propagate down the max field count + internalAnalyseCode(flowContext, flowInfo); + } catch (AbortType e) { + this.ignoreFurtherInvestigation = true; + } + return flowInfo; + } + + /** + * Flow analysis for a member innertype + * + */ + public void analyseCode(ClassScope enclosingClassScope) { + + if (ignoreFurtherInvestigation) + return; + try { + // propagate down the max field count + updateMaxFieldCount(); + internalAnalyseCode(null, FlowInfo.initial(maxFieldCount)); + } catch (AbortType e) { + this.ignoreFurtherInvestigation = true; + } + } + + /** + * Flow analysis for a local member innertype + * + */ + public void analyseCode( + ClassScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + if (ignoreFurtherInvestigation) + return; + try { + if (flowInfo.isReachable()) { + bits |= IsReachableMASK; + LocalTypeBinding localType = (LocalTypeBinding) binding; + localType.setConstantPoolName(currentScope.compilationUnitScope().computeConstantPoolName(localType)); + } + manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo); + updateMaxFieldCount(); // propagate down the max field count + internalAnalyseCode(flowContext, flowInfo); + } catch (AbortType e) { + this.ignoreFurtherInvestigation = true; + } + } + + /** + * Flow analysis for a package member type + * + */ + public void analyseCode(CompilationUnitScope unitScope) { + + if (ignoreFurtherInvestigation) + return; + try { + internalAnalyseCode(null, FlowInfo.initial(maxFieldCount)); + } catch (AbortType e) { + this.ignoreFurtherInvestigation = true; + } + } + + /* + * Check for constructor vs. method with no return type. + * Answers true if at least one constructor is defined + */ + public boolean checkConstructors(Parser parser) { + + //if a constructor has not the name of the type, + //convert it into a method with 'null' as its return type + boolean hasConstructor = false; + if (methods != null) { + for (int i = methods.length; --i >= 0;) { + AbstractMethodDeclaration am; + if ((am = methods[i]).isConstructor()) { + if (!CharOperation.equals(am.selector, name)) { + // the constructor was in fact a method with no return type + // unless an explicit constructor call was supplied + ConstructorDeclaration c = (ConstructorDeclaration) am; + if (c.constructorCall == null || c.constructorCall.isImplicitSuper()) { //changed to a method + MethodDeclaration m = parser.convertToMethodDeclaration(c, this.compilationResult); + methods[i] = m; + } + } else { + if (this.isInterface()) { + // report the problem and continue the parsing + parser.problemReporter().interfaceCannotHaveConstructors( + (ConstructorDeclaration) am); + } + hasConstructor = true; + } + } + } + } + return hasConstructor; + } + + public CompilationResult compilationResult() { + + return this.compilationResult; + } + + public ConstructorDeclaration createsInternalConstructor( + boolean needExplicitConstructorCall, + boolean needToInsert) { + + //Add to method'set, the default constuctor that just recall the + //super constructor with no arguments + //The arguments' type will be positionned by the TC so just use + //the default int instead of just null (consistency purpose) + + //the constructor + ConstructorDeclaration constructor = new ConstructorDeclaration(this.compilationResult); + constructor.isDefaultConstructor = true; + constructor.selector = name; + if (modifiers != AccDefault) { + constructor.modifiers = + (((this.bits & ASTNode.IsMemberTypeMASK) != 0) && (modifiers & AccPrivate) != 0) + ? AccDefault + : modifiers & AccVisibilityMASK; + } + + //if you change this setting, please update the + //SourceIndexer2.buildTypeDeclaration(TypeDeclaration,char[]) method + constructor.declarationSourceStart = constructor.sourceStart = sourceStart; + constructor.declarationSourceEnd = + constructor.sourceEnd = constructor.bodyEnd = sourceEnd; + + //the super call inside the constructor + if (needExplicitConstructorCall) { + constructor.constructorCall = SuperReference.implicitSuperConstructorCall(); + constructor.constructorCall.sourceStart = sourceStart; + constructor.constructorCall.sourceEnd = sourceEnd; + } + + //adding the constructor in the methods list + if (needToInsert) { + if (methods == null) { + methods = new AbstractMethodDeclaration[] { constructor }; + } else { + AbstractMethodDeclaration[] newMethods; + System.arraycopy( + methods, + 0, + newMethods = new AbstractMethodDeclaration[methods.length + 1], + 1, + methods.length); + newMethods[0] = constructor; + methods = newMethods; + } + } + return constructor; + } + + // anonymous type constructor creation + public MethodBinding createsInternalConstructorWithBinding(MethodBinding inheritedConstructorBinding) { + + //Add to method'set, the default constuctor that just recall the + //super constructor with the same arguments + String baseName = "$anonymous"; //$NON-NLS-1$ + TypeBinding[] argumentTypes = inheritedConstructorBinding.parameters; + int argumentsLength = argumentTypes.length; + //the constructor + ConstructorDeclaration cd = new ConstructorDeclaration(this.compilationResult); + cd.selector = new char[] { 'x' }; //no maining + cd.sourceStart = sourceStart; + cd.sourceEnd = sourceEnd; + cd.modifiers = modifiers & AccVisibilityMASK; + cd.isDefaultConstructor = true; + + if (argumentsLength > 0) { + Argument[] arguments = (cd.arguments = new Argument[argumentsLength]); + for (int i = argumentsLength; --i >= 0;) { + arguments[i] = new Argument((baseName + i).toCharArray(), 0L, null /*type ref*/, AccDefault); + } + } + + //the super call inside the constructor + cd.constructorCall = SuperReference.implicitSuperConstructorCall(); + cd.constructorCall.sourceStart = sourceStart; + cd.constructorCall.sourceEnd = sourceEnd; + + if (argumentsLength > 0) { + Expression[] args; + args = cd.constructorCall.arguments = new Expression[argumentsLength]; + for (int i = argumentsLength; --i >= 0;) { + args[i] = new SingleNameReference((baseName + i).toCharArray(), 0L); + } + } + + //adding the constructor in the methods list + if (methods == null) { + methods = new AbstractMethodDeclaration[] { cd }; + } else { + AbstractMethodDeclaration[] newMethods; + System.arraycopy( + methods, + 0, + newMethods = new AbstractMethodDeclaration[methods.length + 1], + 1, + methods.length); + newMethods[0] = cd; + methods = newMethods; + } + + //============BINDING UPDATE========================== + cd.binding = new MethodBinding( + cd.modifiers, //methodDeclaration + argumentsLength == 0 ? NoParameters : argumentTypes, //arguments bindings + inheritedConstructorBinding.thrownExceptions, //exceptions + binding); //declaringClass + + cd.scope = new MethodScope(scope, cd, true); + cd.bindArguments(); + cd.constructorCall.resolve(cd.scope); + + if (binding.methods == null) { + binding.methods = new MethodBinding[] { cd.binding }; + } else { + MethodBinding[] newMethods; + System.arraycopy( + binding.methods, + 0, + newMethods = new MethodBinding[binding.methods.length + 1], + 1, + binding.methods.length); + newMethods[0] = cd.binding; + binding.methods = newMethods; + } + //=================================================== + + return cd.binding; + } + + /* + * Find the matching parse node, answers null if nothing found + */ + public FieldDeclaration declarationOf(FieldBinding fieldBinding) { + + if (fieldBinding != null) { + for (int i = 0, max = this.fields.length; i < max; i++) { + FieldDeclaration fieldDecl; + if ((fieldDecl = this.fields[i]).binding == fieldBinding) + return fieldDecl; + } + } + return null; + } + + /* + * Find the matching parse node, answers null if nothing found + */ + public TypeDeclaration declarationOf(MemberTypeBinding memberTypeBinding) { + + if (memberTypeBinding != null) { + for (int i = 0, max = this.memberTypes.length; i < max; i++) { + TypeDeclaration memberTypeDecl; + if ((memberTypeDecl = this.memberTypes[i]).binding == memberTypeBinding) + return memberTypeDecl; + } + } + return null; + } + + /* + * Find the matching parse node, answers null if nothing found + */ + public AbstractMethodDeclaration declarationOf(MethodBinding methodBinding) { + + if (methodBinding != null) { + for (int i = 0, max = this.methods.length; i < max; i++) { + AbstractMethodDeclaration methodDecl; + + if ((methodDecl = this.methods[i]).binding == methodBinding) + return methodDecl; + } + } + return null; + } + + /* + * Finds the matching type amoung this type's member types. + * Returns null if no type with this name is found. + * The type name is a compound name relative to this type + * eg. if this type is X and we're looking for Y.X.A.B + * then a type name would be {X, A, B} + */ + public TypeDeclaration declarationOfType(char[][] typeName) { + + int typeNameLength = typeName.length; + if (typeNameLength < 1 || !CharOperation.equals(typeName[0], this.name)) { + return null; + } + if (typeNameLength == 1) { + return this; + } + char[][] subTypeName = new char[typeNameLength - 1][]; + System.arraycopy(typeName, 1, subTypeName, 0, typeNameLength - 1); + for (int i = 0; i < this.memberTypes.length; i++) { + TypeDeclaration typeDecl = this.memberTypes[i].declarationOfType(subTypeName); + if (typeDecl != null) { + return typeDecl; + } + } + return null; + } + + /** + * Generic bytecode generation for type + */ + public void generateCode(ClassFile enclosingClassFile) { + + if (hasBeenGenerated) + return; + hasBeenGenerated = true; + if (ignoreFurtherInvestigation) { + if (binding == null) + return; + ClassFile.createProblemType( + this, + scope.referenceCompilationUnit().compilationResult); + return; + } + try { + // create the result for a compiled type + ClassFile classFile = new ClassFile(binding, enclosingClassFile, false); + // generate all fiels + classFile.addFieldInfos(); + + // record the inner type inside its own .class file to be able + // to generate inner classes attributes + if (binding.isMemberType()) + classFile.recordEnclosingTypeAttributes(binding); + if (binding.isLocalType()) { + enclosingClassFile.recordNestedLocalAttribute(binding); + classFile.recordNestedLocalAttribute(binding); + } + if (memberTypes != null) { + for (int i = 0, max = memberTypes.length; i < max; i++) { + // record the inner type inside its own .class file to be able + // to generate inner classes attributes + classFile.recordNestedMemberAttribute(memberTypes[i].binding); + memberTypes[i].generateCode(scope, classFile); + } + } + // generate all methods + classFile.setForMethodInfos(); + if (methods != null) { + for (int i = 0, max = methods.length; i < max; i++) { + methods[i].generateCode(scope, classFile); + } + } + + classFile.generateMissingAbstractMethods(this.missingAbstractMethods, scope.referenceCompilationUnit().compilationResult); + + // generate all methods + classFile.addSpecialMethods(); + + if (ignoreFurtherInvestigation) { // trigger problem type generation for code gen errors + throw new AbortType(scope.referenceCompilationUnit().compilationResult, null); + } + + // finalize the compiled type result + classFile.addAttributes(); + scope.referenceCompilationUnit().compilationResult.record( + binding.constantPoolName(), + classFile); + } catch (AbortType e) { + if (binding == null) + return; + ClassFile.createProblemType( + this, + scope.referenceCompilationUnit().compilationResult); + } + } + + /** + * Bytecode generation for a local inner type (API as a normal statement code gen) + */ + public void generateCode(BlockScope blockScope, CodeStream codeStream) { + + if ((this.bits & IsReachableMASK) == 0) { + return; + } + if (hasBeenGenerated) return; + int pc = codeStream.position; + if (binding != null) ((NestedTypeBinding) binding).computeSyntheticArgumentSlotSizes(); + generateCode(codeStream.classFile); + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + /** + * Bytecode generation for a member inner type + */ + public void generateCode(ClassScope classScope, ClassFile enclosingClassFile) { + + if (hasBeenGenerated) return; + if (binding != null) ((NestedTypeBinding) binding).computeSyntheticArgumentSlotSizes(); + generateCode(enclosingClassFile); + } + + /** + * Bytecode generation for a package member + */ + public void generateCode(CompilationUnitScope unitScope) { + + generateCode((ClassFile) null); + } + + public boolean hasErrors() { + return this.ignoreFurtherInvestigation; + } + + /** + * Common flow analysis for all types + * + */ + public void internalAnalyseCode(FlowContext flowContext, FlowInfo flowInfo) { + + if (this.binding.isPrivate() && !this.binding.isPrivateUsed()) { + if (!scope.referenceCompilationUnit().compilationResult.hasSyntaxError()) { + scope.problemReporter().unusedPrivateType(this); + } + } + + InitializationFlowContext initializerContext = new InitializationFlowContext(null, this, initializerScope); + InitializationFlowContext staticInitializerContext = new InitializationFlowContext(null, this, staticInitializerScope); + FlowInfo nonStaticFieldInfo = flowInfo.copy().unconditionalInits().discardFieldInitializations(); + FlowInfo staticFieldInfo = flowInfo.copy().unconditionalInits().discardFieldInitializations(); + if (fields != null) { + for (int i = 0, count = fields.length; i < count; i++) { + FieldDeclaration field = fields[i]; + if (field.isStatic()) { + /*if (field.isField()){ + staticInitializerContext.handledExceptions = NoExceptions; // no exception is allowed jls8.3.2 + } else {*/ + staticInitializerContext.handledExceptions = AnyException; // tolerate them all, and record them + /*}*/ + staticFieldInfo = + field.analyseCode( + staticInitializerScope, + staticInitializerContext, + staticFieldInfo); + // in case the initializer is not reachable, use a reinitialized flowInfo and enter a fake reachable + // branch, since the previous initializer already got the blame. + if (staticFieldInfo == FlowInfo.DEAD_END) { + staticInitializerScope.problemReporter().initializerMustCompleteNormally(field); + staticFieldInfo = FlowInfo.initial(maxFieldCount).setReachMode(FlowInfo.UNREACHABLE); + } + } else { + /*if (field.isField()){ + initializerContext.handledExceptions = NoExceptions; // no exception is allowed jls8.3.2 + } else {*/ + initializerContext.handledExceptions = AnyException; // tolerate them all, and record them + /*}*/ + nonStaticFieldInfo = + field.analyseCode(initializerScope, initializerContext, nonStaticFieldInfo); + // in case the initializer is not reachable, use a reinitialized flowInfo and enter a fake reachable + // branch, since the previous initializer already got the blame. + if (nonStaticFieldInfo == FlowInfo.DEAD_END) { + initializerScope.problemReporter().initializerMustCompleteNormally(field); + nonStaticFieldInfo = FlowInfo.initial(maxFieldCount).setReachMode(FlowInfo.UNREACHABLE); + } + } + } + } + if (memberTypes != null) { + for (int i = 0, count = memberTypes.length; i < count; i++) { + if (flowContext != null){ // local type + memberTypes[i].analyseCode(scope, flowContext, nonStaticFieldInfo.copy()); + } else { + memberTypes[i].analyseCode(scope); + } + } + } + if (methods != null) { + UnconditionalFlowInfo outerInfo = flowInfo.copy().unconditionalInits().discardFieldInitializations(); + FlowInfo constructorInfo = nonStaticFieldInfo.unconditionalInits().discardNonFieldInitializations().addInitializationsFrom(outerInfo); + for (int i = 0, count = methods.length; i < count; i++) { + AbstractMethodDeclaration method = methods[i]; + if (method.ignoreFurtherInvestigation) + continue; + if (method.isInitializationMethod()) { + if (method.isStatic()) { // + method.analyseCode( + scope, + staticInitializerContext, + staticFieldInfo.unconditionalInits().discardNonFieldInitializations().addInitializationsFrom(outerInfo)); + } else { // constructor + method.analyseCode(scope, initializerContext, constructorInfo.copy()); + } + } else { // regular method + method.analyseCode(scope, null, flowInfo.copy()); + } + } + } + } + + public boolean isInterface() { + + return (modifiers & AccInterface) != 0; + } + + /* + * Access emulation for a local type + * force to emulation of access to direct enclosing instance. + * By using the initializer scope, we actually only request an argument emulation, the + * field is not added until actually used. However we will force allocations to be qualified + * with an enclosing instance. + * 15.9.2 + */ + public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) { + + if (!flowInfo.isReachable()) return; + NestedTypeBinding nestedType = (NestedTypeBinding) binding; + + MethodScope methodScope = currentScope.methodScope(); + if (!methodScope.isStatic && !methodScope.isConstructorCall){ + + nestedType.addSyntheticArgumentAndField(binding.enclosingType()); + } + // add superclass enclosing instance arg for anonymous types (if necessary) + if (binding.isAnonymousType()) { + ReferenceBinding superclassBinding = binding.superclass; + if (superclassBinding.enclosingType() != null && !superclassBinding.isStatic()) { + if (!superclassBinding.isLocalType() + || ((NestedTypeBinding)superclassBinding).getSyntheticField(superclassBinding.enclosingType(), true) != null){ + + nestedType.addSyntheticArgument(superclassBinding.enclosingType()); + } + } + } + } + + /* + * Access emulation for a local member type + * force to emulation of access to direct enclosing instance. + * By using the initializer scope, we actually only request an argument emulation, the + * field is not added until actually used. However we will force allocations to be qualified + * with an enclosing instance. + * + * Local member cannot be static. + */ + public void manageEnclosingInstanceAccessIfNecessary(ClassScope currentScope, FlowInfo flowInfo) { + + if (!flowInfo.isReachable()) return; + NestedTypeBinding nestedType = (NestedTypeBinding) binding; + nestedType.addSyntheticArgumentAndField(binding.enclosingType()); + } + + /** + * A will be requested as soon as static fields or assertions are present. It will be eliminated during + * classfile creation if no bytecode was actually produced based on some optimizations/compiler settings. + */ + public final boolean needClassInitMethod() { + + // always need a when assertions are present + if ((this.bits & AddAssertionMASK) != 0) + return true; + if (fields == null) + return false; + if (isInterface()) + return true; // fields are implicitly statics + for (int i = fields.length; --i >= 0;) { + FieldDeclaration field = fields[i]; + //need to test the modifier directly while there is no binding yet + if ((field.modifiers & AccStatic) != 0) + return true; + } + return false; + } + + public void parseMethod(Parser parser, CompilationUnitDeclaration unit) { + + //connect method bodies + if (unit.ignoreMethodBodies) + return; + + //members + if (memberTypes != null) { + int length = memberTypes.length; + for (int i = 0; i < length; i++) + memberTypes[i].parseMethod(parser, unit); + } + + //methods + if (methods != null) { + int length = methods.length; + for (int i = 0; i < length; i++) + methods[i].parseStatements(parser, unit); + } + + //initializers + if (fields != null) { + int length = fields.length; + for (int i = 0; i < length; i++) { + if (fields[i] instanceof Initializer) { + ((Initializer) fields[i]).parseStatements(parser, this, unit); + } + } + } + } + + public StringBuffer print(int indent, StringBuffer output) { + + if ((this.bits & IsAnonymousTypeMASK) == 0) { + printIndent(indent, output); + printHeader(0, output); + } + return printBody(indent, output); + } + + public StringBuffer printBody(int indent, StringBuffer output) { + + output.append(" {"); //$NON-NLS-1$ + if (memberTypes != null) { + for (int i = 0; i < memberTypes.length; i++) { + if (memberTypes[i] != null) { + output.append('\n'); + memberTypes[i].print(indent + 1, output); + } + } + } + if (fields != null) { + for (int fieldI = 0; fieldI < fields.length; fieldI++) { + if (fields[fieldI] != null) { + output.append('\n'); + fields[fieldI].print(indent + 1, output); + } + } + } + if (methods != null) { + for (int i = 0; i < methods.length; i++) { + if (methods[i] != null) { + output.append('\n'); + methods[i].print(indent + 1, output); + } + } + } + output.append('\n'); + return printIndent(indent, output).append('}'); + } + + public StringBuffer printHeader(int indent, StringBuffer output) { + + printModifiers(this.modifiers, output); + output.append(isInterface() ? "interface " : "class "); //$NON-NLS-1$ //$NON-NLS-2$ + output.append(name); + if (superclass != null) { + output.append(" extends "); //$NON-NLS-1$ + superclass.print(0, output); + } + if (superInterfaces != null && superInterfaces.length > 0) { + output.append(isInterface() ? " extends " : " implements ");//$NON-NLS-2$ //$NON-NLS-1$ + for (int i = 0; i < superInterfaces.length; i++) { + if (i > 0) output.append( ", "); //$NON-NLS-1$ + superInterfaces[i].print(0, output); + } + } + return output; + } + + public StringBuffer printStatement(int tab, StringBuffer output) { + return print(tab, output); + } + + public void resolve() { + + if (this.binding == null) { + this.ignoreFurtherInvestigation = true; + return; + } + try { + if ((this.bits & UndocumentedEmptyBlockMASK) != 0) { + this.scope.problemReporter().undocumentedEmptyBlock(this.bodyStart-1, this.bodyEnd); + } + // check superclass & interfaces + if (this.binding.superclass != null) // watch out for Object ! (and other roots) + if (isTypeUseDeprecated(this.binding.superclass, this.scope)) + this.scope.problemReporter().deprecatedType(this.binding.superclass, this.superclass); + if (this.superInterfaces != null) + for (int i = this.superInterfaces.length; --i >= 0;) + if (this.superInterfaces[i].resolvedType != null) + if (isTypeUseDeprecated(this.superInterfaces[i].resolvedType, this.scope)) + this.scope.problemReporter().deprecatedType( + this.superInterfaces[i].resolvedType, + this.superInterfaces[i]); + this.maxFieldCount = 0; + int lastVisibleFieldID = -1; + if (this.fields != null) { + for (int i = 0, count = this.fields.length; i < count; i++) { + FieldDeclaration field = this.fields[i]; + if (field.isField()) { + if (field.binding == null) { + // still discover secondary errors + if (field.initialization != null) field.initialization.resolve(field.isStatic() ? this.staticInitializerScope : this.initializerScope); + this.ignoreFurtherInvestigation = true; + continue; + } + this.maxFieldCount++; + lastVisibleFieldID = field.binding.id; + } else { // initializer + ((Initializer) field).lastVisibleFieldID = lastVisibleFieldID + 1; + } + field.resolve(field.isStatic() ? this.staticInitializerScope : this.initializerScope); + } + } + if (this.memberTypes != null) { + for (int i = 0, count = this.memberTypes.length; i < count; i++) { + this.memberTypes[i].resolve(this.scope); + } + } + int missingAbstractMethodslength = this.missingAbstractMethods == null ? 0 : this.missingAbstractMethods.length; + int methodsLength = this.methods == null ? 0 : this.methods.length; + if ((methodsLength + missingAbstractMethodslength) > 0xFFFF) { + this.scope.problemReporter().tooManyMethods(this); + } + + if (this.methods != null) { + for (int i = 0, count = this.methods.length; i < count; i++) { + this.methods[i].resolve(this.scope); + } + } + // Resolve javadoc + if (this.javadoc != null) { + if (this.scope != null) { + this.javadoc.resolve(this.scope); + } + } else if (this.binding != null && !this.binding.isLocalType()) { + this.scope.problemReporter().javadocMissing(this.sourceStart, this.sourceEnd, this.binding.modifiers); + } + + } catch (AbortType e) { + this.ignoreFurtherInvestigation = true; + return; + } + } + + public void resolve(BlockScope blockScope) { + // local type declaration + + // need to build its scope first and proceed with binding's creation + if ((this.bits & IsAnonymousTypeMASK) == 0) blockScope.addLocalType(this); + + if (binding != null) { + // remember local types binding for innerclass emulation propagation + blockScope.referenceCompilationUnit().record((LocalTypeBinding)binding); + + // binding is not set if the receiver could not be created + resolve(); + updateMaxFieldCount(); + } + } + + public void resolve(ClassScope upperScope) { + // member scopes are already created + // request the construction of a binding if local member type + + if (binding != null && binding instanceof LocalTypeBinding) { + // remember local types binding for innerclass emulation propagation + upperScope.referenceCompilationUnit().record((LocalTypeBinding)binding); + } + resolve(); + updateMaxFieldCount(); + } + + public void resolve(CompilationUnitScope upperScope) { + // top level : scope are already created + + resolve(); + updateMaxFieldCount(); + } + + public void tagAsHavingErrors() { + ignoreFurtherInvestigation = true; + } + + + /** + * Iteration for a package member type + * + */ + public void traverse( + ASTVisitor visitor, + CompilationUnitScope unitScope) { + + if (ignoreFurtherInvestigation) + return; + try { + if (visitor.visit(this, unitScope)) { + if (superclass != null) + superclass.traverse(visitor, scope); + if (superInterfaces != null) { + int superInterfaceLength = superInterfaces.length; + for (int i = 0; i < superInterfaceLength; i++) + superInterfaces[i].traverse(visitor, scope); + } + if (memberTypes != null) { + int memberTypesLength = memberTypes.length; + for (int i = 0; i < memberTypesLength; i++) + memberTypes[i].traverse(visitor, scope); + } + if (fields != null) { + int fieldsLength = fields.length; + for (int i = 0; i < fieldsLength; i++) { + FieldDeclaration field; + if ((field = fields[i]).isStatic()) { + field.traverse(visitor, staticInitializerScope); + } else { + field.traverse(visitor, initializerScope); + } + } + } + if (methods != null) { + int methodsLength = methods.length; + for (int i = 0; i < methodsLength; i++) + methods[i].traverse(visitor, scope); + } + } + visitor.endVisit(this, unitScope); + } catch (AbortType e) { + // silent abort + } + } + + /** + * Iteration for a local innertype + * + */ + public void traverse(ASTVisitor visitor, BlockScope blockScope) { + if (ignoreFurtherInvestigation) + return; + try { + if (visitor.visit(this, blockScope)) { + if (superclass != null) + superclass.traverse(visitor, scope); + if (superInterfaces != null) { + int superInterfaceLength = superInterfaces.length; + for (int i = 0; i < superInterfaceLength; i++) + superInterfaces[i].traverse(visitor, scope); + } + if (memberTypes != null) { + int memberTypesLength = memberTypes.length; + for (int i = 0; i < memberTypesLength; i++) + memberTypes[i].traverse(visitor, scope); + } + if (fields != null) { + int fieldsLength = fields.length; + for (int i = 0; i < fieldsLength; i++) { + FieldDeclaration field; + if ((field = fields[i]).isStatic()) { + // local type cannot have static fields + } else { + field.traverse(visitor, initializerScope); + } + } + } + if (methods != null) { + int methodsLength = methods.length; + for (int i = 0; i < methodsLength; i++) + methods[i].traverse(visitor, scope); + } + } + visitor.endVisit(this, blockScope); + } catch (AbortType e) { + // silent abort + } + } + + /** + * Iteration for a member innertype + * + */ + public void traverse(ASTVisitor visitor, ClassScope classScope) { + if (ignoreFurtherInvestigation) + return; + try { + if (visitor.visit(this, classScope)) { + if (superclass != null) + superclass.traverse(visitor, scope); + if (superInterfaces != null) { + int superInterfaceLength = superInterfaces.length; + for (int i = 0; i < superInterfaceLength; i++) + superInterfaces[i].traverse(visitor, scope); + } + if (memberTypes != null) { + int memberTypesLength = memberTypes.length; + for (int i = 0; i < memberTypesLength; i++) + memberTypes[i].traverse(visitor, scope); + } + if (fields != null) { + int fieldsLength = fields.length; + for (int i = 0; i < fieldsLength; i++) { + FieldDeclaration field; + if ((field = fields[i]).isStatic()) { + field.traverse(visitor, staticInitializerScope); + } else { + field.traverse(visitor, initializerScope); + } + } + } + if (methods != null) { + int methodsLength = methods.length; + for (int i = 0; i < methodsLength; i++) + methods[i].traverse(visitor, scope); + } + } + visitor.endVisit(this, classScope); + } catch (AbortType e) { + // silent abort + } + } + + /** + * MaxFieldCount's computation is necessary so as to reserve space for + * the flow info field portions. It corresponds to the maximum amount of + * fields this class or one of its innertypes have. + * + * During name resolution, types are traversed, and the max field count is recorded + * on the outermost type. It is then propagated down during the flow analysis. + * + * This method is doing either up/down propagation. + */ + void updateMaxFieldCount() { + + if (binding == null) + return; // error scenario + TypeDeclaration outerMostType = scope.outerMostClassScope().referenceType(); + if (maxFieldCount > outerMostType.maxFieldCount) { + outerMostType.maxFieldCount = maxFieldCount; // up + } else { + maxFieldCount = outerMostType.maxFieldCount; // down + } + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/TypeReference.java b/src/java/org/eclipse/jdt/internal/compiler/ast/TypeReference.java new file mode 100644 index 0000000..2e8e10c --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/TypeReference.java @@ -0,0 +1,136 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.flow.FlowContext; +import org.eclipse.jdt.internal.compiler.flow.FlowInfo; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public abstract class TypeReference extends Expression { + +public TypeReference() { + super () ; + } + +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + return flowInfo; +} + +// allows us to trap completion & selection nodes +public void aboutToResolve(Scope scope) { + // default implementation: do nothing +} +/* + * Answer a base type reference (can be an array of base type). + */ +public static final TypeReference baseTypeReference(int baseType, int dim) { + + if (dim == 0) { + switch (baseType) { + case (T_void) : + return new SingleTypeReference(VoidBinding.simpleName, 0); + case (T_boolean) : + return new SingleTypeReference(BooleanBinding.simpleName, 0); + case (T_char) : + return new SingleTypeReference(CharBinding.simpleName, 0); + case (T_float) : + return new SingleTypeReference(FloatBinding.simpleName, 0); + case (T_double) : + return new SingleTypeReference(DoubleBinding.simpleName, 0); + case (T_byte) : + return new SingleTypeReference(ByteBinding.simpleName, 0); + case (T_short) : + return new SingleTypeReference(ShortBinding.simpleName, 0); + case (T_int) : + return new SingleTypeReference(IntBinding.simpleName, 0); + default : //T_long + return new SingleTypeReference(LongBinding.simpleName, 0); + } + } + switch (baseType) { + case (T_void) : + return new ArrayTypeReference(VoidBinding.simpleName, dim, 0); + case (T_boolean) : + return new ArrayTypeReference(BooleanBinding.simpleName, dim, 0); + case (T_char) : + return new ArrayTypeReference(CharBinding.simpleName, dim, 0); + case (T_float) : + return new ArrayTypeReference(FloatBinding.simpleName, dim, 0); + case (T_double) : + return new ArrayTypeReference(DoubleBinding.simpleName, dim, 0); + case (T_byte) : + return new ArrayTypeReference(ByteBinding.simpleName, dim, 0); + case (T_short) : + return new ArrayTypeReference(ShortBinding.simpleName, dim, 0); + case (T_int) : + return new ArrayTypeReference(IntBinding.simpleName, dim, 0); + default : //T_long + return new ArrayTypeReference(LongBinding.simpleName, dim, 0); + } +} +public abstract TypeReference copyDims(int dim); +public int dimensions() { + return 0; +} +public abstract TypeBinding getTypeBinding(Scope scope); +/** + * @return char[][] + */ +public abstract char [][] getTypeName() ; +public boolean isTypeReference() { + return true; +} +public TypeBinding resolveType(BlockScope blockScope) { + // handle the error here + this.constant = NotAConstant; + if (this.resolvedType != null) { // is a shared type reference which was already resolved + if (!this.resolvedType.isValidBinding()) + return null; // already reported error + } else { + this.resolvedType = getTypeBinding(blockScope); + if (!this.resolvedType.isValidBinding()) { + reportInvalidType(blockScope); + return null; + } + if (isTypeUseDeprecated(this.resolvedType, blockScope)) { + reportDeprecatedType(blockScope); + } + } + return this.resolvedType; +} + +public TypeBinding resolveType(ClassScope classScope) { + // handle the error here + this.constant = NotAConstant; + if (this.resolvedType != null) { // is a shared type reference which was already resolved + if (!this.resolvedType.isValidBinding()) + return null; // already reported error + } else { + this.resolvedType = getTypeBinding(classScope); + if (!this.resolvedType.isValidBinding()) { + reportInvalidType(classScope); + return null; + } + if (isTypeUseDeprecated(this.resolvedType, classScope)) { + reportDeprecatedType(classScope); + } + } + return this.resolvedType; +} +protected void reportInvalidType(Scope scope) { + scope.problemReporter().invalidType(this, this.resolvedType); +} +protected void reportDeprecatedType(Scope scope) { + scope.problemReporter().deprecatedType(this.resolvedType, this); +} +public abstract void traverse(ASTVisitor visitor, ClassScope classScope); +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/UnaryExpression.java b/src/java/org/eclipse/jdt/internal/compiler/ast/UnaryExpression.java new file mode 100644 index 0000000..1e3a2fc --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/UnaryExpression.java @@ -0,0 +1,301 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class UnaryExpression extends OperatorExpression { + + public Expression expression; + public Constant optimizedBooleanConstant; + + public UnaryExpression(Expression expression, int operator) { + this.expression = expression; + this.bits |= operator << OperatorSHIFT; // encode operator + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + if (((bits & OperatorMASK) >> OperatorSHIFT) == NOT) { + return this.expression + .analyseCode(currentScope, flowContext, flowInfo) + .asNegatedCondition(); + } else { + return this.expression.analyseCode(currentScope, flowContext, flowInfo); + } + } + + public Constant optimizedBooleanConstant() { + + return this.optimizedBooleanConstant == null + ? this.constant + : this.optimizedBooleanConstant; + } + + /** + * Code generation for an unary operation + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ + public void generateCode( + BlockScope currentScope, + CodeStream codeStream, + boolean valueRequired) { + + int pc = codeStream.position; + Label falseLabel, endifLabel; + if (this.constant != Constant.NotAConstant) { + // inlined value + if (valueRequired) { + codeStream.generateConstant(this.constant, this.implicitConversion); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + switch ((bits & OperatorMASK) >> OperatorSHIFT) { + case NOT : + switch (this.expression.implicitConversion >> 4) /* runtime type */ { + case T_boolean : + // ! + // Generate code for the condition + this.expression.generateOptimizedBoolean( + currentScope, + codeStream, + null, + (falseLabel = new Label(codeStream)), + valueRequired); + if (valueRequired) { + codeStream.iconst_0(); + if (falseLabel.hasForwardReferences()) { + codeStream.goto_(endifLabel = new Label(codeStream)); + codeStream.decrStackSize(1); + falseLabel.place(); + codeStream.iconst_1(); + endifLabel.place(); + } + } else { // 6596: if (!(a && b)){} - must still place falseLabel + falseLabel.place(); + } + break; + } + break; + case TWIDDLE : + switch (this.expression.implicitConversion >> 4 /* runtime */ + ) { + case T_int : + // ~int + this.expression.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + codeStream.iconst_m1(); + codeStream.ixor(); + } + break; + case T_long : + this.expression.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + codeStream.ldc2_w(-1L); + codeStream.lxor(); + } + } + break; + case MINUS : + // - + if (this.constant != NotAConstant) { + if (valueRequired) { + switch (this.expression.implicitConversion >> 4){ /* runtime */ + case T_int : + codeStream.generateInlinedValue(this.constant.intValue() * -1); + break; + case T_float : + codeStream.generateInlinedValue(this.constant.floatValue() * -1.0f); + break; + case T_long : + codeStream.generateInlinedValue(this.constant.longValue() * -1L); + break; + case T_double : + codeStream.generateInlinedValue(this.constant.doubleValue() * -1.0); + } + } + } else { + this.expression.generateCode(currentScope, codeStream, valueRequired); + if (valueRequired) { + switch (expression.implicitConversion >> 4){ /* runtime type */ + case T_int : + codeStream.ineg(); + break; + case T_float : + codeStream.fneg(); + break; + case T_long : + codeStream.lneg(); + break; + case T_double : + codeStream.dneg(); + } + } + } + break; + case PLUS : + this.expression.generateCode(currentScope, codeStream, valueRequired); + } + if (valueRequired) { + codeStream.generateImplicitConversion(this.implicitConversion); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + /** + * Boolean operator code generation + * Optimized operations are: &&, ||, <, <=, >, >=, &, |, ^ + */ + public void generateOptimizedBoolean( + BlockScope currentScope, + CodeStream codeStream, + Label trueLabel, + Label falseLabel, + boolean valueRequired) { + + if ((this.constant != Constant.NotAConstant) && (this.constant.typeID() == T_boolean)) { + super.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + return; + } + if (((this.bits & OperatorMASK) >> OperatorSHIFT) == NOT) { + this.expression.generateOptimizedBoolean( + currentScope, + codeStream, + falseLabel, + trueLabel, + valueRequired); + } else { + super.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + valueRequired); + } + } + + public StringBuffer printExpressionNoParenthesis(int indent, StringBuffer output) { + + output.append(operatorToString()).append(' '); + return this.expression.printExpression(0, output); + } + + public TypeBinding resolveType(BlockScope scope) { + + boolean expressionIsCast; + if ((expressionIsCast = this.expression instanceof CastExpression) == true) this.expression.bits |= IgnoreNeedForCastCheckMASK; // will check later on + TypeBinding expressionType = this.expression.resolveType(scope); + if (expressionType == null) { + this.constant = NotAConstant; + return null; + } + int expressionTypeId = expressionType.id; + if (expressionTypeId > 15) { + this.constant = NotAConstant; + scope.problemReporter().invalidOperator(this, expressionType); + return null; + } + + int tableId; + switch ((bits & OperatorMASK) >> OperatorSHIFT) { + case NOT : + tableId = AND_AND; + break; + case TWIDDLE : + tableId = LEFT_SHIFT; + break; + default : + tableId = MINUS; + } //+ and - cases + + // the code is an int + // (cast) left Op (cast) rigth --> result + // 0000 0000 0000 0000 0000 + // <<16 <<12 <<8 <<4 <<0 + int operatorSignature = OperatorSignatures[tableId][(expressionTypeId << 4) + expressionTypeId]; + this.expression.implicitConversion = operatorSignature >>> 12; + this.bits |= operatorSignature & 0xF; + switch (operatorSignature & 0xF) { // only switch on possible result type..... + case T_boolean : + this.resolvedType = BooleanBinding; + break; + case T_byte : + this.resolvedType = ByteBinding; + break; + case T_char : + this.resolvedType = CharBinding; + break; + case T_double : + this.resolvedType = DoubleBinding; + break; + case T_float : + this.resolvedType = FloatBinding; + break; + case T_int : + this.resolvedType = IntBinding; + break; + case T_long : + this.resolvedType = LongBinding; + break; + default : //error........ + this.constant = Constant.NotAConstant; + if (expressionTypeId != T_undefined) + scope.problemReporter().invalidOperator(this, expressionType); + return null; + } + // compute the constant when valid + if (this.expression.constant != Constant.NotAConstant) { + this.constant = + Constant.computeConstantOperation( + this.expression.constant, + expressionTypeId, + (bits & OperatorMASK) >> OperatorSHIFT); + } else { + this.constant = Constant.NotAConstant; + if (((bits & OperatorMASK) >> OperatorSHIFT) == NOT) { + Constant cst = expression.optimizedBooleanConstant(); + if (cst != Constant.NotAConstant) + this.optimizedBooleanConstant = Constant.fromValue(!cst.booleanValue()); + } + } + if (expressionIsCast) { + // check need for operand cast + CastExpression.checkNeedForArgumentCast(scope, tableId, operatorSignature, this.expression, expressionTypeId); + } + return this.resolvedType; + } + + public void traverse( + ASTVisitor visitor, + BlockScope blockScope) { + + if (visitor.visit(this, blockScope)) { + this.expression.traverse(visitor, blockScope); + } + visitor.endVisit(this, blockScope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java b/src/java/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java new file mode 100644 index 0000000..b7e1441 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java @@ -0,0 +1,237 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class WhileStatement extends Statement { + + public Expression condition; + public Statement action; + private Label breakLabel, continueLabel; + int preCondInitStateIndex = -1; + int condIfTrueInitStateIndex = -1; + int mergedInitStateIndex = -1; + + public WhileStatement(Expression condition, Statement action, int s, int e) { + + this.condition = condition; + this.action = action; + // remember useful empty statement + if (action instanceof EmptyStatement) action.bits |= IsUsefulEmptyStatementMASK; + sourceStart = s; + sourceEnd = e; + } + + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo) { + + breakLabel = new Label(); + continueLabel = new Label(); + + Constant cst = this.condition.constant; + boolean isConditionTrue = cst != NotAConstant && cst.booleanValue() == true; + boolean isConditionFalse = cst != NotAConstant && cst.booleanValue() == false; + + cst = this.condition.optimizedBooleanConstant(); + boolean isConditionOptimizedTrue = cst != NotAConstant && cst.booleanValue() == true; + boolean isConditionOptimizedFalse = cst != NotAConstant && cst.booleanValue() == false; + + preCondInitStateIndex = + currentScope.methodScope().recordInitializationStates(flowInfo); + LoopingFlowContext condLoopContext; + FlowInfo postCondInfo = + this.condition.analyseCode( + currentScope, + (condLoopContext = + new LoopingFlowContext(flowContext, this, null, null, currentScope)), + flowInfo); + + LoopingFlowContext loopingContext; + FlowInfo actionInfo; + if (action == null + || (action.isEmptyBlock() && currentScope.environment().options.complianceLevel <= ClassFileConstants.JDK1_3)) { + condLoopContext.complainOnFinalAssignmentsInLoop(currentScope, postCondInfo); + if (isConditionTrue) { + return FlowInfo.DEAD_END; + } else { + FlowInfo mergedInfo = postCondInfo.initsWhenFalse().unconditionalInits(); + if (isConditionOptimizedTrue){ + mergedInfo.setReachMode(FlowInfo.UNREACHABLE); + } + mergedInitStateIndex = + currentScope.methodScope().recordInitializationStates(mergedInfo); + return mergedInfo; + } + } else { + // in case the condition was inlined to false, record the fact that there is no way to reach any + // statement inside the looping action + loopingContext = + new LoopingFlowContext( + flowContext, + this, + breakLabel, + continueLabel, + currentScope); + if (isConditionFalse) { + actionInfo = FlowInfo.DEAD_END; + } else { + actionInfo = postCondInfo.initsWhenTrue().copy(); + if (isConditionOptimizedFalse){ + actionInfo.setReachMode(FlowInfo.UNREACHABLE); + } + } + + // for computing local var attributes + condIfTrueInitStateIndex = + currentScope.methodScope().recordInitializationStates( + postCondInfo.initsWhenTrue()); + + if (!this.action.complainIfUnreachable(actionInfo, currentScope, false)) { + actionInfo = this.action.analyseCode(currentScope, loopingContext, actionInfo); + } + + // code generation can be optimized when no need to continue in the loop + if (!actionInfo.isReachable() && !loopingContext.initsOnContinue.isReachable()) { + continueLabel = null; + } else { + // TODO (philippe) should simplify in one Loop context + condLoopContext.complainOnFinalAssignmentsInLoop(currentScope, postCondInfo); + actionInfo = actionInfo.mergedWith(loopingContext.initsOnContinue.unconditionalInits()); + loopingContext.complainOnFinalAssignmentsInLoop(currentScope, actionInfo); + } + } + + // end of loop + FlowInfo mergedInfo = FlowInfo.mergedOptimizedBranches( + loopingContext.initsOnBreak, + isConditionOptimizedTrue, + postCondInfo.initsWhenFalse(), + isConditionOptimizedFalse, + !isConditionTrue /*while(true); unreachable(); */); + mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo); + return mergedInfo; + } + + /** + * While code generation + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + */ + public void generateCode(BlockScope currentScope, CodeStream codeStream) { + + if ((bits & IsReachableMASK) == 0) { + return; + } + int pc = codeStream.position; + breakLabel.initialize(codeStream); + + // generate condition + if (continueLabel == null) { + // no need to reverse condition + if (condition.constant == NotAConstant) { + condition.generateOptimizedBoolean( + currentScope, + codeStream, + null, + breakLabel, + true); + } + } else { + continueLabel.initialize(codeStream); + if (!(((condition.constant != NotAConstant) + && (condition.constant.booleanValue() == true)) + || (action == null) + || action.isEmptyBlock())) { + int jumpPC = codeStream.position; + codeStream.goto_(continueLabel); + codeStream.recordPositionsFrom(jumpPC, condition.sourceStart); + } + } + // generate the action + Label actionLabel; + (actionLabel = new Label(codeStream)).place(); + if (action != null) { + // Required to fix 1PR0XVS: LFRE:WINNT - Compiler: variable table for method appears incorrect + if (condIfTrueInitStateIndex != -1) { + // insert all locals initialized inside the condition into the action generated prior to the condition + codeStream.addDefinitelyAssignedVariables( + currentScope, + condIfTrueInitStateIndex); + } + action.generateCode(currentScope, codeStream); + // May loose some local variable initializations : affecting the local variable attributes + if (preCondInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + preCondInitStateIndex); + } + + } + // output condition and branch back to the beginning of the repeated action + if (continueLabel != null) { + continueLabel.place(); + condition.generateOptimizedBoolean( + currentScope, + codeStream, + actionLabel, + null, + true); + } + breakLabel.place(); + + // May loose some local variable initializations : affecting the local variable attributes + if (mergedInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables(currentScope, mergedInitStateIndex); + codeStream.addDefinitelyAssignedVariables(currentScope, mergedInitStateIndex); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + } + + public void resolve(BlockScope scope) { + + TypeBinding type = condition.resolveTypeExpecting(scope, BooleanBinding); + condition.implicitWidening(type, type); + if (action != null) + action.resolve(scope); + } + + public StringBuffer printStatement(int tab, StringBuffer output) { + + printIndent(tab, output).append("while ("); //$NON-NLS-1$ + condition.printExpression(0, output).append(')'); + if (action == null) + output.append(';'); + else + action.printStatement(tab + 1, output); + return output; + } + + public void traverse( + ASTVisitor visitor, + BlockScope blockScope) { + + if (visitor.visit(this, blockScope)) { + condition.traverse(visitor, blockScope); + if (action != null) + action.traverse(visitor, blockScope); + } + visitor.endVisit(this, blockScope); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/classfmt/ClassFileConstants.java b/src/java/org/eclipse/jdt/internal/compiler/classfmt/ClassFileConstants.java new file mode 100644 index 0000000..127b0cd --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/classfmt/ClassFileConstants.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.classfmt; + +import org.eclipse.jdt.internal.compiler.env.*; + +public interface ClassFileConstants extends IConstants { + + int Utf8Tag = 1; + int IntegerTag = 3; + int FloatTag = 4; + int LongTag = 5; + int DoubleTag = 6; + int ClassTag = 7; + int StringTag = 8; + int FieldRefTag = 9; + int MethodRefTag = 10; + int InterfaceMethodRefTag = 11; + int NameAndTypeTag = 12; + + int ConstantMethodRefFixedSize = 5; + int ConstantClassFixedSize = 3; + int ConstantDoubleFixedSize = 9; + int ConstantFieldRefFixedSize = 5; + int ConstantFloatFixedSize = 5; + int ConstantIntegerFixedSize = 5; + int ConstantInterfaceMethodRefFixedSize = 5; + int ConstantLongFixedSize = 9; + int ConstantStringFixedSize = 3; + int ConstantUtf8FixedSize = 3; + int ConstantNameAndTypeFixedSize = 5; + + int MAJOR_VERSION_1_1 = 45; + int MAJOR_VERSION_1_2 = 46; + int MAJOR_VERSION_1_3 = 47; + int MAJOR_VERSION_1_4 = 48; + int MAJOR_VERSION_1_5 = 49; + + int MINOR_VERSION_0 = 0; + int MINOR_VERSION_1 = 1; + int MINOR_VERSION_2 = 2; + int MINOR_VERSION_3 = 3; + + // JDK 1.1 -> 1.5, comparable value allowing to check both major/minor version at once 1.4.1 > 1.4.0 + // 16 unsigned bits for major, then 16 bits for minor + long JDK1_1 = ((long)ClassFileConstants.MAJOR_VERSION_1_1 << 16) + ClassFileConstants.MINOR_VERSION_3; // 1.1. is 45.3 + long JDK1_2 = ((long)ClassFileConstants.MAJOR_VERSION_1_2 << 16) + ClassFileConstants.MINOR_VERSION_0; + long JDK1_3 = ((long)ClassFileConstants.MAJOR_VERSION_1_3 << 16) + ClassFileConstants.MINOR_VERSION_0; + long JDK1_4 = ((long)ClassFileConstants.MAJOR_VERSION_1_4 << 16) + ClassFileConstants.MINOR_VERSION_0; + long JDK1_5 = ((long)ClassFileConstants.MAJOR_VERSION_1_5 << 16) + ClassFileConstants.MINOR_VERSION_0; + + // jdk level used to denote future releases: optional behavior is not enabled for now, but may become so. In order to enable these, + // search for references to this constant, and change it to one of the official JDT constants above. + long JDK_DEFERRED = Long.MAX_VALUE; +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java b/src/java/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java new file mode 100644 index 0000000..6899fa0 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java @@ -0,0 +1,824 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.classfmt; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.codegen.AttributeNamesConstants; +import org.eclipse.jdt.internal.compiler.env.*; +import org.eclipse.jdt.internal.compiler.impl.Constant; +import org.eclipse.jdt.internal.compiler.lookup.TypeIds; +import org.eclipse.jdt.internal.compiler.util.Util; + +public class ClassFileReader extends ClassFileStruct implements AttributeNamesConstants, IBinaryType { + private int constantPoolCount; + private int[] constantPoolOffsets; + private long version; + private int accessFlags; + private char[] className; + private char[] superclassName; + private int interfacesCount; + private char[][] interfaceNames; + private int fieldsCount; + private FieldInfo[] fields; + private int methodsCount; + private MethodInfo[] methods; + private InnerClassInfo[] innerInfos; + private char[] sourceFileName; + // initialized in case the .class file is a nested type + private InnerClassInfo innerInfo; + private char[] classFileName; + private int classNameIndex; + private int innerInfoIndex; +/** + * @param classFileBytes byte[] + * Actual bytes of a .class file + * + * @param fileName char[] + * Actual name of the file that contains the bytes, can be null + * + * @param fullyInitialize boolean + * Flag to fully initialize the new object + * @exception ClassFormatException + */ +public ClassFileReader(byte[] classFileBytes, char[] fileName, boolean fullyInitialize) throws ClassFormatException { + // This method looks ugly but is actually quite simple, the constantPool is constructed + // in 3 passes. All non-primitive constant pool members that usually refer to other members + // by index are tweaked to have their value in inst vars, this minor cost at read-time makes + // all subsequent uses of the constant pool element faster. + super(classFileBytes, 0); + this.classFileName = fileName; + int readOffset = 10; + try { + this.version = ((long)this.u2At(6) << 16) + this.u2At(4); // major<<16 + minor + constantPoolCount = this.u2At(8); + // Pass #1 - Fill in all primitive constants + this.constantPoolOffsets = new int[constantPoolCount]; + for (int i = 1; i < constantPoolCount; i++) { + int tag = this.u1At(readOffset); + switch (tag) { + case Utf8Tag : + this.constantPoolOffsets[i] = readOffset; + readOffset += u2At(readOffset + 1); + readOffset += ConstantUtf8FixedSize; + break; + case IntegerTag : + this.constantPoolOffsets[i] = readOffset; + readOffset += ConstantIntegerFixedSize; + break; + case FloatTag : + this.constantPoolOffsets[i] = readOffset; + readOffset += ConstantFloatFixedSize; + break; + case LongTag : + this.constantPoolOffsets[i] = readOffset; + readOffset += ConstantLongFixedSize; + i++; + break; + case DoubleTag : + this.constantPoolOffsets[i] = readOffset; + readOffset += ConstantDoubleFixedSize; + i++; + break; + case ClassTag : + this.constantPoolOffsets[i] = readOffset; + readOffset += ConstantClassFixedSize; + break; + case StringTag : + this.constantPoolOffsets[i] = readOffset; + readOffset += ConstantStringFixedSize; + break; + case FieldRefTag : + this.constantPoolOffsets[i] = readOffset; + readOffset += ConstantFieldRefFixedSize; + break; + case MethodRefTag : + this.constantPoolOffsets[i] = readOffset; + readOffset += ConstantMethodRefFixedSize; + break; + case InterfaceMethodRefTag : + this.constantPoolOffsets[i] = readOffset; + readOffset += ConstantInterfaceMethodRefFixedSize; + break; + case NameAndTypeTag : + this.constantPoolOffsets[i] = readOffset; + readOffset += ConstantNameAndTypeFixedSize; + } + } + // Read and validate access flags + this.accessFlags = u2At(readOffset); + readOffset += 2; + + // Read the classname, use exception handlers to catch bad format + this.classNameIndex = u2At(readOffset); + this.className = getConstantClassNameAt(this.classNameIndex); + readOffset += 2; + + // Read the superclass name, can be null for java.lang.Object + int superclassNameIndex = u2At(readOffset); + readOffset += 2; + // if superclassNameIndex is equals to 0 there is no need to set a value for the + // field this.superclassName. null is fine. + if (superclassNameIndex != 0) { + this.superclassName = getConstantClassNameAt(superclassNameIndex); + } + + // Read the interfaces, use exception handlers to catch bad format + this.interfacesCount = u2At(readOffset); + readOffset += 2; + if (this.interfacesCount != 0) { + this.interfaceNames = new char[this.interfacesCount][]; + for (int i = 0; i < this.interfacesCount; i++) { + this.interfaceNames[i] = getConstantClassNameAt(u2At(readOffset)); + readOffset += 2; + } + } + // Read the this.fields, use exception handlers to catch bad format + this.fieldsCount = u2At(readOffset); + readOffset += 2; + if (this.fieldsCount != 0) { + FieldInfo field; + this.fields = new FieldInfo[this.fieldsCount]; + for (int i = 0; i < this.fieldsCount; i++) { + field = new FieldInfo(reference, this.constantPoolOffsets, readOffset); + this.fields[i] = field; + readOffset += field.sizeInBytes(); + } + } + // Read the this.methods + this.methodsCount = u2At(readOffset); + readOffset += 2; + if (this.methodsCount != 0) { + this.methods = new MethodInfo[this.methodsCount]; + MethodInfo method; + for (int i = 0; i < this.methodsCount; i++) { + method = new MethodInfo(reference, this.constantPoolOffsets, readOffset); + this.methods[i] = method; + readOffset += method.sizeInBytes(); + } + } + + // Read the attributes + int attributesCount = u2At(readOffset); + readOffset += 2; + + for (int i = 0; i < attributesCount; i++) { + int utf8Offset = this.constantPoolOffsets[u2At(readOffset)]; + char[] attributeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); + if (CharOperation.equals(attributeName, DeprecatedName)) { + this.accessFlags |= AccDeprecated; + } else { + if (CharOperation.equals(attributeName, InnerClassName)) { + int innerOffset = readOffset + 6; + int number_of_classes = u2At(innerOffset); + if (number_of_classes != 0) { + innerOffset+= 2; + this.innerInfos = new InnerClassInfo[number_of_classes]; + for (int j = 0; j < number_of_classes; j++) { + this.innerInfos[j] = + new InnerClassInfo(reference, this.constantPoolOffsets, innerOffset); + if (this.classNameIndex == this.innerInfos[j].innerClassNameIndex) { + this.innerInfo = this.innerInfos[j]; + this.innerInfoIndex = j; + } + innerOffset += 8; + } + } + } else { + if (CharOperation.equals(attributeName, SourceName)) { + utf8Offset = this.constantPoolOffsets[u2At(readOffset + 6)]; + this.sourceFileName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); + } else { + if (CharOperation.equals(attributeName, SyntheticName)) { + this.accessFlags |= AccSynthetic; + } + } + } + } + readOffset += (6 + u4At(readOffset + 2)); + } + if (fullyInitialize) { + this.initialize(); + } + } catch(ClassFormatException e) { + throw e; + } catch (Exception e) { + throw new ClassFormatException( + ClassFormatException.ErrTruncatedInput, + readOffset); + } +} + +/** + * @param classFileBytes Actual bytes of a .class file + * @param fileName Actual name of the file that contains the bytes, can be null + * + * @exception ClassFormatException + */ +public ClassFileReader(byte classFileBytes[], char[] fileName) throws ClassFormatException { + this(classFileBytes, fileName, false); +} + +/** + * Answer the receiver's access flags. The value of the access_flags + * item is a mask of modifiers used with class and interface declarations. + * @return int + */ +public int accessFlags() { + return this.accessFlags; +} +/** + * Answer the char array that corresponds to the class name of the constant class. + * constantPoolIndex is the index in the constant pool that is a constant class entry. + * + * @param constantPoolIndex int + * @return char[] + */ +private char[] getConstantClassNameAt(int constantPoolIndex) { + int utf8Offset = this.constantPoolOffsets[u2At(this.constantPoolOffsets[constantPoolIndex] + 1)]; + return utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); +} +/** + * Answer the int array that corresponds to all the offsets of each entry in the constant pool + * + * @return int[] + */ +public int[] getConstantPoolOffsets() { + return this.constantPoolOffsets; +} +/* + * Answer the resolved compoundName of the enclosing type + * or null if the receiver is a top level type. + */ +public char[] getEnclosingTypeName() { + if (this.innerInfo != null && !this.isAnonymous()) { + return this.innerInfo.getEnclosingTypeName(); + } + return null; +} +/** + * Answer the receiver's this.fields or null if the array is empty. + * @return org.eclipse.jdt.internal.compiler.api.IBinaryField[] + */ +public IBinaryField[] getFields() { + return this.fields; +} +/** + * Answer the file name which defines the type. + * The format is unspecified. + */ +public char[] getFileName() { + return this.classFileName; +} +/** + * Answer the source name if the receiver is a inner type. Return null if it is an anonymous class or if the receiver is a top-level class. + * e.g. + * public class A { + * public class B { + * } + * public void foo() { + * class C {} + * } + * public Runnable bar() { + * return new Runnable() { + * public void run() {} + * }; + * } + * } + * It returns {'B'} for the member A$B + * It returns null for A + * It returns {'C'} for the local class A$1$C + * It returns null for the anonymous A$1 + * @return char[] + */ +public char[] getInnerSourceName() { + if (this.innerInfo != null) + return this.innerInfo.getSourceName(); + return null; +} +/** + * Answer the resolved names of the receiver's interfaces in the + * class file format as specified in section 4.2 of the Java 2 VM spec + * or null if the array is empty. + * + * For example, java.lang.String is java/lang/String. + * @return char[][] + */ +public char[][] getInterfaceNames() { + return this.interfaceNames; +} +/** + * Answer the receiver's nested types or null if the array is empty. + * + * This nested type info is extracted from the inner class attributes. + * Ask the name environment to find a member type using its compound name + * @return org.eclipse.jdt.internal.compiler.api.IBinaryNestedType[] + */ +public IBinaryNestedType[] getMemberTypes() { + // we might have some member types of the current type + if (this.innerInfos == null) return null; + + int length = this.innerInfos.length; + int startingIndex = this.innerInfo != null ? this.innerInfoIndex + 1 : 0; + if (length != startingIndex) { + IBinaryNestedType[] memberTypes = + new IBinaryNestedType[length - this.innerInfoIndex]; + int memberTypeIndex = 0; + for (int i = startingIndex; i < length; i++) { + InnerClassInfo currentInnerInfo = this.innerInfos[i]; + int outerClassNameIdx = currentInnerInfo.outerClassNameIndex; + int innerNameIndex = currentInnerInfo.innerNameIndex; + /* + * Checking that outerClassNameIDx is different from 0 should be enough to determine if an inner class + * attribute entry is a member class, but due to the bug: + * http://dev.eclipse.org/bugs/show_bug.cgi?id=14592 + * we needed to add an extra check. So we check that innerNameIndex is different from 0 as well. + * + * https://bugs.eclipse.org/bugs/show_bug.cgi?id=49879 + * From JavaMail 1.2, the class javax.mail.Folder contains an anonymous class in the + * terminateQueue() method for which the inner attribute is boggus. + * outerClassNameIdx is not 0, innerNameIndex is not 0, but the sourceName length is 0. + * So I added this extra check to filter out this anonymous class from the + * member types. + */ + if (outerClassNameIdx != 0 + && innerNameIndex != 0 + && outerClassNameIdx == this.classNameIndex + && currentInnerInfo.getSourceName().length != 0) { + memberTypes[memberTypeIndex++] = currentInnerInfo; + } + } + if (memberTypeIndex == 0) return null; + if (memberTypeIndex != memberTypes.length) { + // we need to resize the memberTypes array. Some local or anonymous classes + // are present in the current class. + System.arraycopy( + memberTypes, + 0, + (memberTypes = new IBinaryNestedType[memberTypeIndex]), + 0, + memberTypeIndex); + } + return memberTypes; + } + return null; +} +/** + * Answer the receiver's this.methods or null if the array is empty. + * @return org.eclipse.jdt.internal.compiler.api.env.IBinaryMethod[] + */ +public IBinaryMethod[] getMethods() { + return this.methods; +} +/** + * Answer an int whose bits are set according the access constants + * defined by the VM spec. + * Set the AccDeprecated and AccSynthetic bits if necessary + * @return int + */ +public int getModifiers() { + if (this.innerInfo != null) { + if ((this.accessFlags & AccDeprecated) != 0) { + return this.innerInfo.getModifiers() | AccDeprecated; + } else { + return this.innerInfo.getModifiers(); + } + } + return this.accessFlags; +} +/** + * Answer the resolved name of the type in the + * class file format as specified in section 4.2 of the Java 2 VM spec. + * + * For example, java.lang.String is java/lang/String. + * @return char[] + */ +public char[] getName() { + return this.className; +} +/** + * Answer the resolved name of the receiver's superclass in the + * class file format as specified in section 4.2 of the Java 2 VM spec + * or null if it does not have one. + * + * For example, java.lang.String is java/lang/String. + * @return char[] + */ +public char[] getSuperclassName() { + return this.superclassName; +} +/** + * Answer the major/minor version defined in this class file according to the VM spec. + * as a long: (major<<16)+minor + * @return the major/minor version found + */ +public long getVersion() { + return this.version; +} +/** + * Answer true if the receiver is an anonymous type, false otherwise + * + * @return boolean + */ +public boolean isAnonymous() { + if (this.innerInfo == null) return false; + char[] sourceName = this.innerInfo.getSourceName(); + return (sourceName == null || sourceName.length == 0); +} +/** + * Answer whether the receiver contains the resolved binary form + * or the unresolved source form of the type. + * @return boolean + */ +public boolean isBinaryType() { + return true; +} +/** + * Answer true if the receiver is a class. False otherwise. + * @return boolean + */ +public boolean isClass() { + return (getModifiers() & AccInterface) == 0; +} +/** + * Answer true if the receiver is an interface. False otherwise. + * @return boolean + */ +public boolean isInterface() { + return (getModifiers() & AccInterface) != 0; +} +/** + * Answer true if the receiver is a local type, false otherwise + * + * @return boolean + */ +public boolean isLocal() { + if (this.innerInfo == null) return false; + if (this.innerInfo.getEnclosingTypeName() != null) return false; + char[] sourceName = this.innerInfo.getSourceName(); + return (sourceName != null && sourceName.length > 0); +} +/** + * Answer true if the receiver is a member type, false otherwise + * + * @return boolean + */ +public boolean isMember() { + if (this.innerInfo == null) return false; + if (this.innerInfo.getEnclosingTypeName() == null) return false; + char[] sourceName = this.innerInfo.getSourceName(); + return (sourceName != null && sourceName.length > 0); // protection against ill-formed attributes (67600) +} +/** + * Answer true if the receiver is a nested type, false otherwise + * + * @return boolean + */ +public boolean isNestedType() { + return this.innerInfo != null; +} +public static ClassFileReader read(File file) throws ClassFormatException, IOException { + return read(file, false); +} +public static ClassFileReader read(File file, boolean fullyInitialize) throws ClassFormatException, IOException { + byte classFileBytes[] = Util.getFileByteContent(file); + ClassFileReader classFileReader = new ClassFileReader(classFileBytes, file.getAbsolutePath().toCharArray()); + if (fullyInitialize) { + classFileReader.initialize(); + } + return classFileReader; +} +public static ClassFileReader read(String fileName) throws ClassFormatException, java.io.IOException { + return read(fileName, false); +} +public static ClassFileReader read(String fileName, boolean fullyInitialize) throws ClassFormatException, java.io.IOException { + return read(new File(fileName), fullyInitialize); +} +public static ClassFileReader read( + java.util.zip.ZipFile zip, + String filename) + throws ClassFormatException, java.io.IOException { + return read(zip, filename, false); +} +public static ClassFileReader read( + java.util.zip.ZipFile zip, + String filename, + boolean fullyInitialize) + throws ClassFormatException, java.io.IOException { + java.util.zip.ZipEntry ze = zip.getEntry(filename); + if (ze == null) + return null; + byte classFileBytes[] = Util.getZipEntryByteContent(ze, zip); + ClassFileReader classFileReader = new ClassFileReader(classFileBytes, filename.toCharArray()); + if (fullyInitialize) { + classFileReader.initialize(); + } + return classFileReader; +} + +/** + * Answer the source file name attribute. Return null if there is no source file attribute for the receiver. + * + * @return char[] + */ +public char[] sourceFileName() { + return this.sourceFileName; +} +public String toString() { + java.io.ByteArrayOutputStream out = new java.io.ByteArrayOutputStream(); + java.io.PrintWriter print = new java.io.PrintWriter(out); + + print.println(this.getClass().getName() + "{"); //$NON-NLS-1$ + print.println(" this.className: " + new String(getName())); //$NON-NLS-1$ + print.println(" this.superclassName: " + (getSuperclassName() == null ? "null" : new String(getSuperclassName()))); //$NON-NLS-2$ //$NON-NLS-1$ + print.println(" access_flags: " + ClassFileStruct.printTypeModifiers(this.accessFlags()) + "(" + this.accessFlags() + ")"); //$NON-NLS-1$ //$NON-NLS-3$ //$NON-NLS-2$ + + print.flush(); + return out.toString(); +} +/** + * Check if the receiver has structural changes compare to the byte array in argument. + * Structural changes are: + * - modifiers changes for the class, the this.fields or the this.methods + * - signature changes for this.fields or this.methods. + * - changes in the number of this.fields or this.methods + * - changes for field constants + * - changes for thrown exceptions + * - change for the super class or any super interfaces. + * - changes for member types name or modifiers + * If any of these changes occurs, the method returns true. false otherwise. + * The synthetic fields are included and the members are not required to be sorted. + * @param newBytes the bytes of the .class file we want to compare the receiver to + * @return boolean Returns true is there is a structural change between the two .class files, false otherwise + */ +public boolean hasStructuralChanges(byte[] newBytes) { + return hasStructuralChanges(newBytes, true, true); +} +/** + * Check if the receiver has structural changes compare to the byte array in argument. + * Structural changes are: + * - modifiers changes for the class, the this.fields or the this.methods + * - signature changes for this.fields or this.methods. + * - changes in the number of this.fields or this.methods + * - changes for field constants + * - changes for thrown exceptions + * - change for the super class or any super interfaces. + * - changes for member types name or modifiers + * If any of these changes occurs, the method returns true. false otherwise. + * @param newBytes the bytes of the .class file we want to compare the receiver to + * @param orderRequired a boolean indicating whether the members should be sorted or not + * @param excludesSynthetic a boolean indicating whether the synthetic members should be used in the comparison + * @return boolean Returns true is there is a structural change between the two .class files, false otherwise + */ +public boolean hasStructuralChanges(byte[] newBytes, boolean orderRequired, boolean excludesSynthetic) { + try { + ClassFileReader newClassFile = + new ClassFileReader(newBytes, this.classFileName); + // type level comparison + // modifiers + if (this.getModifiers() != newClassFile.getModifiers()) + return true; + // superclass + if (!CharOperation.equals(this.getSuperclassName(), newClassFile.getSuperclassName())) + return true; + // interfaces + char[][] newInterfacesNames = newClassFile.getInterfaceNames(); + if (this.interfaceNames != newInterfacesNames) { // TypeConstants.NoSuperInterfaces + int newInterfacesLength = newInterfacesNames == null ? 0 : newInterfacesNames.length; + if (newInterfacesLength != this.interfacesCount) + return true; + for (int i = 0, max = this.interfacesCount; i < max; i++) + if (!CharOperation.equals(this.interfaceNames[i], newInterfacesNames[i])) + return true; + } + + // member types + IBinaryNestedType[] currentMemberTypes = this.getMemberTypes(); + IBinaryNestedType[] otherMemberTypes = newClassFile.getMemberTypes(); + if (currentMemberTypes != otherMemberTypes) { // TypeConstants.NoMemberTypes + int currentMemberTypeLength = currentMemberTypes == null ? 0 : currentMemberTypes.length; + int otherMemberTypeLength = otherMemberTypes == null ? 0 : otherMemberTypes.length; + if (currentMemberTypeLength != otherMemberTypeLength) + return true; + for (int i = 0; i < currentMemberTypeLength; i++) + if (!CharOperation.equals(currentMemberTypes[i].getName(), otherMemberTypes[i].getName()) + || currentMemberTypes[i].getModifiers() != otherMemberTypes[i].getModifiers()) + return true; + } + + // fields + FieldInfo[] otherFieldInfos = (FieldInfo[]) newClassFile.getFields(); + int otherFieldInfosLength = otherFieldInfos == null ? 0 : otherFieldInfos.length; + boolean compareFields = true; + if (this.fieldsCount == otherFieldInfosLength) { + int i = 0; + for (; i < this.fieldsCount; i++) + if (hasStructuralFieldChanges(this.fields[i], otherFieldInfos[i])) break; + if ((compareFields = i != this.fieldsCount) && !orderRequired && !excludesSynthetic) + return true; + } + if (compareFields) { + if (this.fieldsCount != otherFieldInfosLength && !excludesSynthetic) + return true; + if (orderRequired) { + if (this.fieldsCount != 0) + Arrays.sort(this.fields); + if (otherFieldInfosLength != 0) + Arrays.sort(otherFieldInfos); + } + if (excludesSynthetic) { + if (hasNonSyntheticFieldChanges(this.fields, otherFieldInfos)) + return true; + } else { + for (int i = 0; i < this.fieldsCount; i++) + if (hasStructuralFieldChanges(this.fields[i], otherFieldInfos[i])) + return true; + } + } + + // methods + MethodInfo[] otherMethodInfos = (MethodInfo[]) newClassFile.getMethods(); + int otherMethodInfosLength = otherMethodInfos == null ? 0 : otherMethodInfos.length; + boolean compareMethods = true; + if (this.methodsCount == otherMethodInfosLength) { + int i = 0; + for (; i < this.methodsCount; i++) + if (hasStructuralMethodChanges(this.methods[i], otherMethodInfos[i])) break; + if ((compareMethods = i != this.methodsCount) && !orderRequired && !excludesSynthetic) + return true; + } + if (compareMethods) { + if (this.methodsCount != otherMethodInfosLength && !excludesSynthetic) + return true; + if (orderRequired) { + if (this.methodsCount != 0) + Arrays.sort(this.methods); + if (otherMethodInfosLength != 0) + Arrays.sort(otherMethodInfos); + } + if (excludesSynthetic) { + if (hasNonSyntheticMethodChanges(this.methods, otherMethodInfos)) + return true; + } else { + for (int i = 0; i < this.methodsCount; i++) + if (hasStructuralMethodChanges(this.methods[i], otherMethodInfos[i])) + return true; + } + } + + return false; + } catch (ClassFormatException e) { + return true; + } +} +private boolean hasNonSyntheticFieldChanges(FieldInfo[] currentFieldInfos, FieldInfo[] otherFieldInfos) { + int length1 = currentFieldInfos == null ? 0 : currentFieldInfos.length; + int length2 = otherFieldInfos == null ? 0 : otherFieldInfos.length; + int index1 = 0; + int index2 = 0; + + end : while (index1 < length1 && index2 < length2) { + while (currentFieldInfos[index1].isSynthetic()) { + if (++index1 >= length1) break end; + } + while (otherFieldInfos[index2].isSynthetic()) { + if (++index2 >= length2) break end; + } + if (hasStructuralFieldChanges(currentFieldInfos[index1++], otherFieldInfos[index2++])) + return true; + } + + while (index1 < length1) { + if (!currentFieldInfos[index1++].isSynthetic()) return true; + } + while (index2 < length2) { + if (!otherFieldInfos[index2++].isSynthetic()) return true; + } + return false; +} +private boolean hasStructuralFieldChanges(FieldInfo currentFieldInfo, FieldInfo otherFieldInfo) { + if (currentFieldInfo.getModifiers() != otherFieldInfo.getModifiers()) + return true; + if (!CharOperation.equals(currentFieldInfo.getName(), otherFieldInfo.getName())) + return true; + if (!CharOperation.equals(currentFieldInfo.getTypeName(), otherFieldInfo.getTypeName())) + return true; + if (currentFieldInfo.hasConstant() != otherFieldInfo.hasConstant()) + return true; + if (currentFieldInfo.hasConstant()) { + Constant currentConstant = currentFieldInfo.getConstant(); + Constant otherConstant = otherFieldInfo.getConstant(); + if (currentConstant.typeID() != otherConstant.typeID()) + return true; + if (!currentConstant.getClass().equals(otherConstant.getClass())) + return true; + switch (currentConstant.typeID()) { + case TypeIds.T_int : + return currentConstant.intValue() != otherConstant.intValue(); + case TypeIds.T_byte : + return currentConstant.byteValue() != otherConstant.byteValue(); + case TypeIds.T_short : + return currentConstant.shortValue() != otherConstant.shortValue(); + case TypeIds.T_char : + return currentConstant.charValue() != otherConstant.charValue(); + case TypeIds.T_long : + return currentConstant.longValue() != otherConstant.longValue(); + case TypeIds.T_float : + return currentConstant.floatValue() != otherConstant.floatValue(); + case TypeIds.T_double : + return currentConstant.doubleValue() != otherConstant.doubleValue(); + case TypeIds.T_boolean : + return currentConstant.booleanValue() != otherConstant.booleanValue(); + case TypeIds.T_String : + return !currentConstant.stringValue().equals(otherConstant.stringValue()); + } + } + return false; +} +private boolean hasNonSyntheticMethodChanges(MethodInfo[] currentMethodInfos, MethodInfo[] otherMethodInfos) { + int length1 = currentMethodInfos == null ? 0 : currentMethodInfos.length; + int length2 = otherMethodInfos == null ? 0 : otherMethodInfos.length; + int index1 = 0; + int index2 = 0; + + MethodInfo m; + end : while (index1 < length1 && index2 < length2) { + while ((m = currentMethodInfos[index1]).isSynthetic() || m.isClinit()) { + if (++index1 >= length1) break end; + } + while ((m = otherMethodInfos[index2]).isSynthetic() || m.isClinit()) { + if (++index2 >= length2) break end; + } + if (hasStructuralMethodChanges(currentMethodInfos[index1++], otherMethodInfos[index2++])) + return true; + } + + while (index1 < length1) { + if (!((m = currentMethodInfos[index1++]).isSynthetic() || m.isClinit())) return true; + } + while (index2 < length2) { + if (!((m = otherMethodInfos[index2++]).isSynthetic() || m.isClinit())) return true; + } + return false; +} +private boolean hasStructuralMethodChanges(MethodInfo currentMethodInfo, MethodInfo otherMethodInfo) { + if (currentMethodInfo.getModifiers() != otherMethodInfo.getModifiers()) + return true; + if (!CharOperation.equals(currentMethodInfo.getSelector(), otherMethodInfo.getSelector())) + return true; + if (!CharOperation.equals(currentMethodInfo.getMethodDescriptor(), otherMethodInfo.getMethodDescriptor())) + return true; + + char[][] currentThrownExceptions = currentMethodInfo.getExceptionTypeNames(); + char[][] otherThrownExceptions = otherMethodInfo.getExceptionTypeNames(); + if (currentThrownExceptions != otherThrownExceptions) { // TypeConstants.NoExceptions + int currentThrownExceptionsLength = currentThrownExceptions == null ? 0 : currentThrownExceptions.length; + int otherThrownExceptionsLength = otherThrownExceptions == null ? 0 : otherThrownExceptions.length; + if (currentThrownExceptionsLength != otherThrownExceptionsLength) + return true; + for (int k = 0; k < currentThrownExceptionsLength; k++) + if (!CharOperation.equals(currentThrownExceptions[k], otherThrownExceptions[k])) + return true; + } + return false; +} +/** + * This method is used to fully initialize the contents of the receiver. All methodinfos, fields infos + * will be therefore fully initialized and we can get rid of the bytes. + */ +private void initialize() throws ClassFormatException { + try { + for (int i = 0, max = fieldsCount; i < max; i++) { + fields[i].initialize(); + } + for (int i = 0, max = methodsCount; i < max; i++) { + methods[i].initialize(); + } + if (innerInfos != null) { + for (int i = 0, max = innerInfos.length; i < max; i++) { + innerInfos[i].initialize(); + } + } + this.reset(); + } catch(RuntimeException e) { + ClassFormatException exception = new ClassFormatException(e, this.classFileName); + throw exception; + } +} +protected void reset() { + this.constantPoolOffsets = null; + super.reset(); +} + +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/classfmt/ClassFileStruct.java b/src/java/org/eclipse/jdt/internal/compiler/classfmt/ClassFileStruct.java new file mode 100644 index 0000000..caaaa17 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/classfmt/ClassFileStruct.java @@ -0,0 +1,188 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.classfmt; + +abstract public class ClassFileStruct implements ClassFileConstants { + byte[] reference; + int structOffset; +public ClassFileStruct(byte classFileBytes[], int off) { + reference = classFileBytes; + structOffset = off; +} +public ClassFileStruct (byte classFileBytes[], int off, boolean verifyStructure) { + reference = classFileBytes; + structOffset = off; +} +public double doubleAt(int relativeOffset) { + return (Double.longBitsToDouble(this.i8At(relativeOffset))); +} +public float floatAt(int relativeOffset) { + return (Float.intBitsToFloat(this.i4At(relativeOffset))); +} +public int i1At(int relativeOffset) { + return reference[relativeOffset + structOffset]; +} +public int i2At(int relativeOffset) { + int position = relativeOffset + structOffset; + return (reference[position++] << 8) + (reference[position] & 0xFF); +} +public int i4At(int relativeOffset) { + int position = relativeOffset + structOffset; + return ((reference[position++] & 0xFF) << 24) + ((reference[position++] & 0xFF) << 16) + ((reference[position++] & 0xFF) << 8) + (reference[position] & 0xFF); +} +public long i8At(int relativeOffset) { + int position = relativeOffset + structOffset; + return (((long) (reference[position++] & 0xFF)) << 56) + + (((long) (reference[position++] & 0xFF)) << 48) + + (((long) (reference[position++] & 0xFF)) << 40) + + (((long) (reference[position++] & 0xFF)) << 32) + + (((long) (reference[position++] & 0xFF)) << 24) + + (((long) (reference[position++] & 0xFF)) << 16) + + (((long) (reference[position++] & 0xFF)) << 8) + + (reference[position++] & 0xFF); +} +public static String printTypeModifiers(int modifiers) { + + java.io.ByteArrayOutputStream out = new java.io.ByteArrayOutputStream(); + java.io.PrintWriter print = new java.io.PrintWriter(out); + + if ((modifiers & AccPublic) != 0) print.print("public "); //$NON-NLS-1$ + if ((modifiers & AccPrivate) != 0) print.print("private "); //$NON-NLS-1$ + if ((modifiers & AccFinal) != 0) print.print("final "); //$NON-NLS-1$ + if ((modifiers & AccSuper) != 0) print.print("super "); //$NON-NLS-1$ + if ((modifiers & AccInterface) != 0) print.print("interface "); //$NON-NLS-1$ + if ((modifiers & AccAbstract) != 0) print.print("abstract "); //$NON-NLS-1$ + print.flush(); + return out.toString(); +} +public int u1At(int relativeOffset) { + return (reference[relativeOffset + structOffset] & 0xFF); +} +public int u2At(int relativeOffset) { + int position = relativeOffset + structOffset; + return ((reference[position++] & 0xFF) << 8) + (reference[position] & 0xFF); +} +public long u4At(int relativeOffset) { + int position = relativeOffset + structOffset; + return (((reference[position++] & 0xFFL) << 24) + ((reference[position++] & 0xFF) << 16) + ((reference[position++] & 0xFF) << 8) + (reference[position] & 0xFF)); +} +public char[] utf8At(int relativeOffset, int bytesAvailable) { + int length = bytesAvailable; + char outputBuf[] = new char[bytesAvailable]; + int outputPos = 0; + int readOffset = this.structOffset + relativeOffset; + + while (length != 0) { + int x = this.reference[readOffset++] & 0xFF; + length--; + if ((0x80 & x) != 0) { + if ((x & 0x20) != 0) { + length-=2; + x = ((x & 0xF) << 12) | ((this.reference[readOffset++] & 0x3F) << 6) | (this.reference[readOffset++] & 0x3F); + } else { + length--; + x = ((x & 0x1F) << 6) | (this.reference[readOffset++] & 0x3F); + } + } + outputBuf[outputPos++] = (char) x; + } + + if (outputPos != bytesAvailable) { + System.arraycopy(outputBuf, 0, (outputBuf = new char[outputPos]), 0, outputPos); + } + return outputBuf; +} + +protected void reset() { + this.reference = null; +} + +public char[] utf8At(int relativeOffset, int bytesAvailable, boolean testValidity) throws ClassFormatException { + int x, y, z; + int length = bytesAvailable; + char outputBuf[] = new char[bytesAvailable]; + int outputPos = 0; + int readOffset = structOffset + relativeOffset; + + while (length != 0) { + x = reference[readOffset++] & 0xFF; + length--; + if ((0x80 & x) != 0) { + if (testValidity) { + if ((0x40 & x) == 0) { + throw new ClassFormatException(ClassFormatException.ErrMalformedUtf8); + } + if (length < 1) { + throw new ClassFormatException(ClassFormatException.ErrMalformedUtf8); + } + } + y = this.reference[readOffset++] & 0xFF; + length--; + if (testValidity) { + if ((y & 0xC0) != 0x80) { + throw new ClassFormatException(ClassFormatException.ErrMalformedUtf8); + } + } + if ((x & 0x20) != 0) { + if (testValidity && (length < 1)) { + throw new ClassFormatException(ClassFormatException.ErrMalformedUtf8); + } + z = this.reference[readOffset++] & 0xFF; + length--; + if (testValidity && ((z & 0xC0) != 0x80)) { + throw new ClassFormatException(ClassFormatException.ErrMalformedUtf8); + } + x = ((x & 0x1F) << 12) + ((y & 0x3F) << 6) + (z & 0x3F); + if (testValidity && (x < 0x0800)) { + throw new ClassFormatException(ClassFormatException.ErrMalformedUtf8); + } + } else { + x = ((x & 0x1F) << 6) + (y & 0x3F); + if (testValidity && !((x == 0) || (x >= 0x80))) { + throw new ClassFormatException(ClassFormatException.ErrMalformedUtf8); + } + } + } else { + if (testValidity && x == 0) { + throw new ClassFormatException(ClassFormatException.ErrMalformedUtf8); + } + } + outputBuf[outputPos++] = (char) x; + } + + if (outputPos != bytesAvailable) { + System.arraycopy(outputBuf, 0, (outputBuf = new char[outputPos]), 0, outputPos); + } + return outputBuf; +} +public static void verifyMethodNameAndSignature(char[] name, char[] signature) throws ClassFormatException { + + // ensure name is not empty + if (name.length == 0) { + throw new ClassFormatException(ClassFormatException.ErrInvalidMethodName); + } + + // if name begins with the < character it must be clinit or init + if (name[0] == '<') { + if (new String(name).equals("") || new String(name).equals("")) { //$NON-NLS-2$ //$NON-NLS-1$ + int signatureLength = signature.length; + if (!((signatureLength > 2) + && (signature[0] == '(') + && (signature[signatureLength - 2] == ')') + && (signature[signatureLength - 1] == 'V'))) { + throw new ClassFormatException(ClassFormatException.ErrInvalidMethodSignature); + } + } else { + throw new ClassFormatException(ClassFormatException.ErrInvalidMethodName); + } + } +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/classfmt/ClassFormatException.java b/src/java/org/eclipse/jdt/internal/compiler/classfmt/ClassFormatException.java new file mode 100644 index 0000000..fd3f30e --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/classfmt/ClassFormatException.java @@ -0,0 +1,130 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Common Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: IBM Corporation - initial API and implementation + ******************************************************************************/ +package org.eclipse.jdt.internal.compiler.classfmt; +import java.io.PrintStream; +import java.io.PrintWriter; +public class ClassFormatException extends Exception { + public static final int ErrBadMagic = 1; + public static final int ErrBadMinorVersion = 2; + public static final int ErrBadMajorVersion = 3; + public static final int ErrBadConstantClass = 4; + public static final int ErrBadConstantString = 5; + public static final int ErrBadConstantNameAndType = 6; + public static final int ErrBadConstantFieldRef = 7; + public static final int ErrBadConstantMethodRef = 8; + public static final int ErrBadConstantInterfaceMethodRef = 9; + public static final int ErrBadConstantPoolIndex = 10; + public static final int ErrBadSuperclassName = 11; + public static final int ErrInterfaceCannotBeFinal = 12; + public static final int ErrInterfaceMustBeAbstract = 13; + public static final int ErrBadModifiers = 14; + public static final int ErrClassCannotBeAbstractFinal = 15; + public static final int ErrBadClassname = 16; + public static final int ErrBadFieldInfo = 17; + public static final int ErrBadMethodInfo = 17; + public static final int ErrEmptyConstantPool = 18; + public static final int ErrMalformedUtf8 = 19; + public static final int ErrUnknownConstantTag = 20; + public static final int ErrTruncatedInput = 21; + public static final int ErrMethodMustBeAbstract = 22; + public static final int ErrMalformedAttribute = 23; + public static final int ErrBadInterface = 24; + public static final int ErrInterfaceMustSubclassObject = 25; + public static final int ErrIncorrectInterfaceMethods = 26; + public static final int ErrInvalidMethodName = 27; + public static final int ErrInvalidMethodSignature = 28; + + private static final long serialVersionUID = 6667458511042774540L; // backward compatible + + private int errorCode; + private int bufferPosition; + private RuntimeException nestedException; + private char[] fileName; + + public ClassFormatException(RuntimeException e, char[] fileName) { + this.nestedException = e; + } + public ClassFormatException(int code) { + errorCode = code; + } + public ClassFormatException(int code, int bufPos) { + errorCode = code; + bufferPosition = bufPos; + } + /** + * @return int + */ + public int getErrorCode() { + return errorCode; + } + /** + * @return int + */ + public int getBufferPosition() { + return bufferPosition; + } + /** + * Returns the underlying Throwable that caused the failure. + * + * @return the wrappered Throwable, or null + * if the direct case of the failure was at the Java model layer + */ + public Throwable getException() { + return this.nestedException; + } + public void printStackTrace() { + printStackTrace(System.err); + } + /** + * Prints this exception's stack trace to the given print stream. + * + * @param output + * the print stream + * @since 3.0 + */ + public void printStackTrace(PrintStream output) { + synchronized (output) { + super.printStackTrace(output); + Throwable throwable = getException(); + if (throwable != null) { + if (this.fileName != null) { + output.print("Caused in "); //$NON-NLS-1$ + output.print(this.fileName); + output.print(" by: "); //$NON-NLS-1$ + } else { + output.print("Caused by: "); //$NON-NLS-1$ + } + throwable.printStackTrace(output); + } + } + } + /** + * Prints this exception's stack trace to the given print writer. + * + * @param output + * the print writer + * @since 3.0 + */ + public void printStackTrace(PrintWriter output) { + synchronized (output) { + super.printStackTrace(output); + Throwable throwable = getException(); + if (throwable != null) { + if (this.fileName != null) { + output.print("Caused in "); //$NON-NLS-1$ + output.print(this.fileName); + output.print(" by: "); //$NON-NLS-1$ + } else { + output.print("Caused by: "); //$NON-NLS-1$ + } + throwable.printStackTrace(output); + } + } + } +} \ No newline at end of file diff --git a/src/java/org/eclipse/jdt/internal/compiler/classfmt/FieldInfo.java b/src/java/org/eclipse/jdt/internal/compiler/classfmt/FieldInfo.java new file mode 100644 index 0000000..26392d8 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/classfmt/FieldInfo.java @@ -0,0 +1,306 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.classfmt; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.codegen.AttributeNamesConstants; +import org.eclipse.jdt.internal.compiler.env.IBinaryField; +import org.eclipse.jdt.internal.compiler.impl.BooleanConstant; +import org.eclipse.jdt.internal.compiler.impl.ByteConstant; +import org.eclipse.jdt.internal.compiler.impl.CharConstant; +import org.eclipse.jdt.internal.compiler.impl.Constant; +import org.eclipse.jdt.internal.compiler.impl.DoubleConstant; +import org.eclipse.jdt.internal.compiler.impl.FloatConstant; +import org.eclipse.jdt.internal.compiler.impl.IntConstant; +import org.eclipse.jdt.internal.compiler.impl.LongConstant; +import org.eclipse.jdt.internal.compiler.impl.ShortConstant; +import org.eclipse.jdt.internal.compiler.impl.StringConstant; +import org.eclipse.jdt.internal.compiler.lookup.TypeIds; +import org.eclipse.jdt.internal.compiler.util.Util; + +public class FieldInfo extends ClassFileStruct implements AttributeNamesConstants, IBinaryField, Comparable, TypeIds { + private Constant constant; + private boolean isDeprecated; + private boolean isSynthetic; + private int[] constantPoolOffsets; + private int accessFlags; + private char[] name; + private char[] signature; + private int attributeBytes; + private Object wrappedConstantValue; +/** + * @param classFileBytes byte[] + * @param offsets int[] + * @param offset int + */ +public FieldInfo (byte classFileBytes[], int offsets[], int offset) { + super(classFileBytes, offset); + constantPoolOffsets = offsets; + accessFlags = -1; + int attributesCount = u2At(6); + int readOffset = 8; + for (int i = 0; i < attributesCount; i++) { + readOffset += (6 + u4At(readOffset + 2)); + } + attributeBytes = readOffset; +} +/** + * Return the constant of the field. + * Return org.eclipse.jdt.internal.compiler.impl.Constant.NotAConstant if there is none. + * @return org.eclipse.jdt.internal.compiler.impl.Constant + */ +public Constant getConstant() { + if (constant == null) { + // read constant + readConstantAttribute(); + } + return constant; +} +/** + * Answer an int whose bits are set according the access constants + * defined by the VM spec. + * Set the AccDeprecated and AccSynthetic bits if necessary + * @return int + */ +public int getModifiers() { + if (accessFlags == -1) { + // compute the accessflag. Don't forget the deprecated attribute + accessFlags = u2At(0); + readDeprecatedAndSyntheticAttributes(); + if (isDeprecated) { + accessFlags |= AccDeprecated; + } + if (isSynthetic) { + accessFlags |= AccSynthetic; + } + } + return accessFlags; +} +/** + * Answer the name of the field. + * @return char[] + */ +public char[] getName() { + if (name == null) { + // read the name + int utf8Offset = constantPoolOffsets[u2At(2)] - structOffset; + name = utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); + } + return name; +} +/** + * Answer the resolved name of the receiver's type in the + * class file format as specified in section 4.3.2 of the Java 2 VM spec. + * + * For example: + * - java.lang.String is Ljava/lang/String; + * - an int is I + * - a 2 dimensional array of strings is [[Ljava/lang/String; + * - an array of floats is [F + * @return char[] + */ +public char[] getTypeName() { + if (signature == null) { + // read the signature + int utf8Offset = constantPoolOffsets[u2At(4)] - structOffset; + signature = utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); + } + return signature; +} +/** + * Return a wrapper that contains the constant of the field. + * @return java.lang.Object + */ +public Object getWrappedConstantValue() { + + if (this.wrappedConstantValue == null) { + if (hasConstant()) { + Constant fieldConstant = getConstant(); + switch (fieldConstant.typeID()) { + case T_int : + this.wrappedConstantValue = new Integer(fieldConstant.intValue()); + break; + case T_byte : + this.wrappedConstantValue = new Byte(fieldConstant.byteValue()); + break; + case T_short : + this.wrappedConstantValue = new Short(fieldConstant.shortValue()); + break; + case T_char : + this.wrappedConstantValue = new Character(fieldConstant.charValue()); + break; + case T_float : + this.wrappedConstantValue = new Float(fieldConstant.floatValue()); + break; + case T_double : + this.wrappedConstantValue = new Double(fieldConstant.doubleValue()); + break; + case T_boolean : + this.wrappedConstantValue = Util.toBoolean(fieldConstant.booleanValue()); + break; + case T_long : + this.wrappedConstantValue = new Long(fieldConstant.longValue()); + break; + case T_String : + this.wrappedConstantValue = fieldConstant.stringValue(); + } + } + } + return this.wrappedConstantValue; +} +/** + * Return true if the field has a constant value attribute, false otherwise. + * @return boolean + */ +public boolean hasConstant() { + return getConstant() != Constant.NotAConstant; +} +/** + * Return true if the field is a synthetic field, false otherwise. + * @return boolean + */ +public boolean isSynthetic() { + return (getModifiers() & AccSynthetic) != 0; +} + +private void readConstantAttribute() { + int attributesCount = u2At(6); + int readOffset = 8; + boolean isConstant = false; + for (int i = 0; i < attributesCount; i++) { + int utf8Offset = constantPoolOffsets[u2At(readOffset)] - structOffset; + char[] attributeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); + if (CharOperation + .equals(attributeName, ConstantValueName)) { + isConstant = true; + // read the right constant + int relativeOffset = constantPoolOffsets[u2At(readOffset + 6)] - structOffset; + switch (u1At(relativeOffset)) { + case IntegerTag : + char[] sign = getTypeName(); + if (sign.length == 1) { + switch (sign[0]) { + case 'Z' : // boolean constant + constant = new BooleanConstant(i4At(relativeOffset + 1) == 1); + break; + case 'I' : // integer constant + constant = new IntConstant(i4At(relativeOffset + 1)); + break; + case 'C' : // char constant + constant = new CharConstant((char) i4At(relativeOffset + 1)); + break; + case 'B' : // byte constant + constant = new ByteConstant((byte) i4At(relativeOffset + 1)); + break; + case 'S' : // short constant + constant = new ShortConstant((short) i4At(relativeOffset + 1)); + break; + default: + constant = Constant.NotAConstant; + } + } else { + constant = Constant.NotAConstant; + } + break; + case FloatTag : + constant = new FloatConstant(floatAt(relativeOffset + 1)); + break; + case DoubleTag : + constant = new DoubleConstant(doubleAt(relativeOffset + 1)); + break; + case LongTag : + constant = new LongConstant(i8At(relativeOffset + 1)); + break; + case StringTag : + utf8Offset = constantPoolOffsets[u2At(relativeOffset + 1)] - structOffset; + constant = + new StringConstant( + String.valueOf(utf8At(utf8Offset + 3, u2At(utf8Offset + 1)))); + break; + } + } + readOffset += (6 + u4At(readOffset + 2)); + } + if (!isConstant) { + constant = Constant.NotAConstant; + } +} +private void readDeprecatedAndSyntheticAttributes() { + int attributesCount = u2At(6); + int readOffset = 8; + for (int i = 0; i < attributesCount; i++) { + int utf8Offset = constantPoolOffsets[u2At(readOffset)] - structOffset; + char[] attributeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); + if (CharOperation.equals(attributeName, DeprecatedName)) { + isDeprecated = true; + } else if (CharOperation.equals(attributeName, SyntheticName)) { + isSynthetic = true; + } + readOffset += (6 + u4At(readOffset + 2)); + } +} +/** + * Answer the size of the receiver in bytes. + * + * @return int + */ +public int sizeInBytes() { + return attributeBytes; +} +public void throwFormatException() throws ClassFormatException { + throw new ClassFormatException(ClassFormatException.ErrBadFieldInfo); +} +public String toString() { + StringBuffer buffer = new StringBuffer(this.getClass().getName()); + int modifiers = getModifiers(); + return buffer + .append("{") //$NON-NLS-1$ + .append( + ((modifiers & AccDeprecated) != 0 ? "deprecated " : "") //$NON-NLS-1$ //$NON-NLS-2$ + + ((modifiers & 0x0001) == 1 ? "public " : "") //$NON-NLS-1$ //$NON-NLS-2$ + + ((modifiers & 0x0002) == 0x0002 ? "private " : "") //$NON-NLS-1$ //$NON-NLS-2$ + + ((modifiers & 0x0004) == 0x0004 ? "protected " : "") //$NON-NLS-1$ //$NON-NLS-2$ + + ((modifiers & 0x0008) == 0x000008 ? "static " : "") //$NON-NLS-1$ //$NON-NLS-2$ + + ((modifiers & 0x0010) == 0x0010 ? "final " : "") //$NON-NLS-1$ //$NON-NLS-2$ + + ((modifiers & 0x0040) == 0x0040 ? "volatile " : "") //$NON-NLS-1$ //$NON-NLS-2$ + + ((modifiers & 0x0080) == 0x0080 ? "transient " : "")) //$NON-NLS-1$ //$NON-NLS-2$ + .append(getTypeName()) + .append(" ") //$NON-NLS-1$ + .append(getName()) + .append(" ") //$NON-NLS-1$ + .append(getConstant()) + .append("}") //$NON-NLS-1$ + .toString(); +} + +public int compareTo(Object o) { + if (!(o instanceof FieldInfo)) { + throw new ClassCastException(); + } + return new String(this.getName()).compareTo(new String(((FieldInfo) o).getName())); +} +/** + * This method is used to fully initialize the contents of the receiver. All methodinfos, fields infos + * will be therefore fully initialized and we can get rid of the bytes. + */ +void initialize() { + getModifiers(); + getName(); + getConstant(); + getTypeName(); + reset(); +} +protected void reset() { + this.constantPoolOffsets = null; + super.reset(); +} + +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/classfmt/InnerClassInfo.java b/src/java/org/eclipse/jdt/internal/compiler/classfmt/InnerClassInfo.java new file mode 100644 index 0000000..476c664 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/classfmt/InnerClassInfo.java @@ -0,0 +1,142 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.classfmt; + +import org.eclipse.jdt.internal.compiler.env.IBinaryNestedType; + +/** + * Describes one entry in the classes table of the InnerClasses attribute. + * See the inner class specification (The class file attribute "InnerClasses"). + */ + +public class InnerClassInfo extends ClassFileStruct implements IBinaryNestedType { + int innerClassNameIndex = -1; + int outerClassNameIndex = -1; + int innerNameIndex = -1; + private char[] innerClassName; + private char[] outerClassName; + private char[] innerName; + private int accessFlags = -1; + private int[] constantPoolOffsets; + private boolean readInnerClassName = false; + private boolean readOuterClassName = false; + private boolean readInnerName = false; +public InnerClassInfo(byte classFileBytes[], int offsets[], int offset) { + super(classFileBytes, offset); + constantPoolOffsets = offsets; + innerClassNameIndex = u2At(0); + outerClassNameIndex = u2At(2); + this.innerNameIndex = u2At(4); +} +/** + * Answer the resolved name of the enclosing type in the + * class file format as specified in section 4.2 of the Java 2 VM spec. + * + * For example, java.lang.String is java/lang/String. + * @return char[] + */ +public char[] getEnclosingTypeName() { + if (!readOuterClassName) { + // read outer class name + readOuterClassName = true; + if (outerClassNameIndex != 0) { + int utf8Offset = + constantPoolOffsets[u2At( + constantPoolOffsets[outerClassNameIndex] - structOffset + 1)] + - structOffset; + outerClassName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); + } + + } + return outerClassName; +} +/** + * Answer an int whose bits are set according the access constants + * defined by the VM spec. + * @return int + */ +public int getModifiers() { + if (accessFlags == -1) { + // read access flag + accessFlags = u2At(6); + } + return accessFlags; +} +/** + * Answer the resolved name of the member type in the + * class file format as specified in section 4.2 of the Java 2 VM spec. + * + * For example, p1.p2.A.M is p1/p2/A$M. + * @return char[] + */ +public char[] getName() { + if (!readInnerClassName) { + // read the inner class name + readInnerClassName = true; + if (innerClassNameIndex != 0) { + int classOffset = constantPoolOffsets[innerClassNameIndex] - structOffset; + int utf8Offset = constantPoolOffsets[u2At(classOffset + 1)] - structOffset; + innerClassName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); + } + } + return innerClassName; +} +/** + * Answer the source name of the member type. + * + * For example, p1.p2.A.M is M. + * @return char[] + */ +public char[] getSourceName() { + if (!this.readInnerName) { + this.readInnerName = true; + if (innerNameIndex != 0) { + int utf8Offset = constantPoolOffsets[innerNameIndex] - structOffset; + innerName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); + } + } + return innerName; +} +/** + * Answer the string representation of the receiver + * @return java.lang.String + */ +public String toString() { + StringBuffer buffer = new StringBuffer(); + if (getName() != null) { + buffer.append(getName()); + } + buffer.append("\n"); //$NON-NLS-1$ + if (getEnclosingTypeName() != null) { + buffer.append(getEnclosingTypeName()); + } + buffer.append("\n"); //$NON-NLS-1$ + if (getSourceName() != null) { + buffer.append(getSourceName()); + } + return buffer.toString(); +} +/** + * This method is used to fully initialize the contents of the receiver. All methodinfos, fields infos + * will be therefore fully initialized and we can get rid of the bytes. + */ +void initialize() { + getModifiers(); + getName(); + getSourceName(); + getEnclosingTypeName(); + reset(); +} +protected void reset() { + this.constantPoolOffsets = null; + super.reset(); +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/classfmt/MethodInfo.java b/src/java/org/eclipse/jdt/internal/compiler/classfmt/MethodInfo.java new file mode 100644 index 0000000..c9255be --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/classfmt/MethodInfo.java @@ -0,0 +1,236 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.classfmt; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.codegen.AttributeNamesConstants; +import org.eclipse.jdt.internal.compiler.env.IBinaryMethod; + +public class MethodInfo extends ClassFileStruct implements IBinaryMethod, AttributeNamesConstants, Comparable { + private char[][] exceptionNames; + private int[] constantPoolOffsets; + private boolean isDeprecated; + private boolean isSynthetic; + private int accessFlags; + private char[] name; + private char[] signature; + private int attributeBytes; + static private final char[][] noException = CharOperation.NO_CHAR_CHAR; +/** + * @param classFileBytes byte[] + * @param offsets int[] + * @param offset int + */ +public MethodInfo (byte classFileBytes[], int offsets[], int offset) { + super(classFileBytes, offset); + constantPoolOffsets = offsets; + accessFlags = -1; + int attributesCount = u2At(6); + int readOffset = 8; + for (int i = 0; i < attributesCount; i++) { + readOffset += (6 + u4At(readOffset + 2)); + } + attributeBytes = readOffset; +} +/** + * @see org.eclipse.jdt.internal.compiler.env.IGenericMethod#getArgumentNames() + */ +public char[][] getArgumentNames() { + return null; +} +/** + * Answer the resolved names of the exception types in the + * class file format as specified in section 4.2 of the Java 2 VM spec + * or null if the array is empty. + * + * For example, java.lang.String is java/lang/String. + * @return char[][] + */ +public char[][] getExceptionTypeNames() { + if (exceptionNames == null) { + readExceptionAttributes(); + } + return exceptionNames; +} +/** + * Answer the receiver's method descriptor which describes the parameter & + * return types as specified in section 4.3.3 of the Java 2 VM spec. + * + * For example: + * - int foo(String) is (Ljava/lang/String;)I + * - void foo(Object[]) is (I)[Ljava/lang/Object; + * @return char[] + */ +public char[] getMethodDescriptor() { + if (signature == null) { + // read the name + int utf8Offset = constantPoolOffsets[u2At(4)] - structOffset; + signature = utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); + } + return signature; +} +/** + * Answer an int whose bits are set according the access constants + * defined by the VM spec. + * Set the AccDeprecated and AccSynthetic bits if necessary + * @return int + */ +public int getModifiers() { + if (accessFlags == -1) { + // compute the accessflag. Don't forget the deprecated attribute + accessFlags = u2At(0); + readDeprecatedAndSyntheticAttributes(); + if (isDeprecated) { + accessFlags |= AccDeprecated; + } + if (isSynthetic) { + accessFlags |= AccSynthetic; + } + } + return accessFlags; +} +/** + * Answer the name of the method. + * + * For a constructor, answer & for a clinit method. + * @return char[] + */ +public char[] getSelector() { + if (name == null) { + // read the name + int utf8Offset = constantPoolOffsets[u2At(2)] - structOffset; + name = utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); + } + return name; +} +/** + * Answer true if the method is a class initializer, false otherwise. + * @return boolean + */ +public boolean isClinit() { + char[] selector = getSelector(); + return selector[0] == '<' && selector.length == 8; // Can only match +} +/** + * Answer true if the method is a constructor, false otherwise. + * @return boolean + */ +public boolean isConstructor() { + char[] selector = getSelector(); + return selector[0] == '<' && selector.length == 6; // Can only match +} +/** + * Return true if the field is a synthetic method, false otherwise. + * @return boolean + */ +public boolean isSynthetic() { + return (getModifiers() & AccSynthetic) != 0; +} +private void readDeprecatedAndSyntheticAttributes() { + int attributesCount = u2At(6); + int readOffset = 8; + for (int i = 0; i < attributesCount; i++) { + int utf8Offset = constantPoolOffsets[u2At(readOffset)] - structOffset; + char[] attributeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); + if (CharOperation.equals(attributeName, DeprecatedName)) { + isDeprecated = true; + } else if (CharOperation.equals(attributeName, SyntheticName)) { + isSynthetic = true; + } + readOffset += (6 + u4At(readOffset + 2)); + } +} +private void readExceptionAttributes() { + int attributesCount = u2At(6); + int readOffset = 8; + for (int i = 0; i < attributesCount; i++) { + int utf8Offset = constantPoolOffsets[u2At(readOffset)] - structOffset; + char[] attributeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); + if (CharOperation.equals(attributeName, ExceptionsName)) { + // read the number of exception entries + int entriesNumber = u2At(readOffset + 6); + // place the readOffset at the beginning of the exceptions table + readOffset += 8; + if (entriesNumber == 0) { + exceptionNames = noException; + } else { + exceptionNames = new char[entriesNumber][]; + for (int j = 0; j < entriesNumber; j++) { + utf8Offset = + constantPoolOffsets[u2At( + constantPoolOffsets[u2At(readOffset)] - structOffset + 1)] + - structOffset; + exceptionNames[j] = utf8At(utf8Offset + 3, u2At(utf8Offset + 1)); + readOffset += 2; + } + } + } else { + readOffset += (6 + u4At(readOffset + 2)); + } + } + if (exceptionNames == null) { + exceptionNames = noException; + } +} +/** + * Answer the size of the receiver in bytes. + * + * @return int + */ +public int sizeInBytes() { + return attributeBytes; +} +public String toString() { + int modifiers = getModifiers(); + StringBuffer buffer = new StringBuffer(this.getClass().getName()); + return buffer + .append("{") //$NON-NLS-1$ + .append( + ((modifiers & AccDeprecated) != 0 ? "deprecated " : "") //$NON-NLS-1$ //$NON-NLS-2$ + + ((modifiers & 0x0001) == 1 ? "public " : "") //$NON-NLS-1$ //$NON-NLS-2$ + + ((modifiers & 0x0002) == 0x0002 ? "private " : "") //$NON-NLS-1$ //$NON-NLS-2$ + + ((modifiers & 0x0004) == 0x0004 ? "protected " : "") //$NON-NLS-1$ //$NON-NLS-2$ + + ((modifiers & 0x0008) == 0x000008 ? "static " : "") //$NON-NLS-1$ //$NON-NLS-2$ + + ((modifiers & 0x0010) == 0x0010 ? "final " : "") //$NON-NLS-1$ //$NON-NLS-2$ + + ((modifiers & 0x0040) == 0x0040 ? "volatile " : "") //$NON-NLS-1$ //$NON-NLS-2$ + + ((modifiers & 0x0080) == 0x0080 ? "transient " : "")) //$NON-NLS-1$ //$NON-NLS-2$ + .append(getSelector()) + .append(getMethodDescriptor()) + .append("}") //$NON-NLS-1$ + .toString(); +} +public int compareTo(Object o) { + if (!(o instanceof MethodInfo)) { + throw new ClassCastException(); + } + + MethodInfo otherMethod = (MethodInfo) o; + int result = new String(this.getSelector()).compareTo(new String(otherMethod.getSelector())); + if (result != 0) return result; + return new String(this.getMethodDescriptor()).compareTo(new String(otherMethod.getMethodDescriptor())); +} + +/** + * This method is used to fully initialize the contents of the receiver. All methodinfos, fields infos + * will be therefore fully initialized and we can get rid of the bytes. + */ +void initialize() { + getModifiers(); + getSelector(); + getMethodDescriptor(); + getExceptionTypeNames(); + reset(); +} +protected void reset() { + this.constantPoolOffsets = null; + super.reset(); +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/codegen/AttributeNamesConstants.java b/src/java/org/eclipse/jdt/internal/compiler/codegen/AttributeNamesConstants.java new file mode 100644 index 0000000..577b9bd --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/codegen/AttributeNamesConstants.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.codegen; + +public interface AttributeNamesConstants { + final char[] SyntheticName = new char[] {'S', 'y', 'n', 't', 'h', 'e', 't', 'i', 'c'}; + final char[] ConstantValueName = new char[] {'C', 'o', 'n', 's', 't', 'a', 'n', 't', 'V', 'a', 'l', 'u', 'e'}; + final char[] LineNumberTableName = new char[] {'L', 'i', 'n', 'e', 'N', 'u', 'm', 'b', 'e', 'r', 'T', 'a', 'b', 'l', 'e'}; + final char[] LocalVariableTableName = new char[] {'L', 'o', 'c', 'a', 'l', 'V', 'a', 'r', 'i', 'a', 'b', 'l', 'e', 'T', 'a', 'b', 'l', 'e'}; + final char[] InnerClassName = new char[] {'I', 'n', 'n', 'e', 'r', 'C', 'l', 'a', 's', 's', 'e', 's'}; + final char[] CodeName = new char[] {'C', 'o', 'd', 'e'}; + final char[] ExceptionsName = new char[] {'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n', 's'}; + final char[] SourceName = new char[] {'S', 'o', 'u', 'r', 'c', 'e', 'F', 'i', 'l', 'e'}; + final char[] DeprecatedName = new char[] {'D', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd'}; +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/codegen/CaseLabel.java b/src/java/org/eclipse/jdt/internal/compiler/codegen/CaseLabel.java new file mode 100644 index 0000000..725588e --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/codegen/CaseLabel.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.codegen; + +public class CaseLabel extends Label { + public int instructionPosition = POS_NOT_SET; + public int backwardsBranch = POS_NOT_SET; +/** + * CaseLabel constructor comment. + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + */ +public CaseLabel(CodeStream codeStream) { + super(codeStream); +} +/* +* Put down a refernece to the array at the location in the codestream. +*/ +void branch() { + if (position == POS_NOT_SET) { + addForwardReference(codeStream.position); + // Leave 4 bytes free to generate the jump offset afterwards + codeStream.position += 4; + codeStream.classFileOffset += 4; + } else { //Position is set. Write it! + codeStream.writeSignedWord(position - codeStream.position + 1); + } +} +/* +* Put down a refernece to the array at the location in the codestream. +*/ +void branchWide() { + if (position == POS_NOT_SET) { + addForwardReference(codeStream.position); + // Leave 4 bytes free to generate the jump offset afterwards + codeStream.position += 4; + } else { //Position is set. Write it! + codeStream.writeSignedWord(position - codeStream.position + 1); + } +} +public boolean isStandardLabel(){ + return false; +} +/* +* Put down a reference to the array at the location in the codestream. +*/ +public void place() { + position = codeStream.position; + if (instructionPosition == POS_NOT_SET) + backwardsBranch = position; + else { + int offset = position - instructionPosition; + for (int i = 0; i < forwardReferenceCount; i++) { + codeStream.writeSignedWord(forwardReferences[i], offset); + } + // add the label int the codeStream labels collection + codeStream.addLabel(this); + } +} +/* +* Put down a refernece to the array at the location in the codestream. +*/ +void placeInstruction() { + if (instructionPosition == POS_NOT_SET) { + instructionPosition = codeStream.position; + if (backwardsBranch != POS_NOT_SET) { + int offset = backwardsBranch - instructionPosition; + for (int i = 0; i < forwardReferenceCount; i++) + codeStream.writeSignedWord(forwardReferences[i], offset); + backwardsBranch = POS_NOT_SET; + } + } +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/codegen/CharArrayCache.java b/src/java/org/eclipse/jdt/internal/compiler/codegen/CharArrayCache.java new file mode 100644 index 0000000..b5f8126 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/codegen/CharArrayCache.java @@ -0,0 +1,184 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.codegen; + +import org.eclipse.jdt.core.compiler.CharOperation; + +public class CharArrayCache { + // to avoid using Enumerations, walk the individual tables skipping nulls + public char[] keyTable[]; + public int valueTable[]; + int elementSize; // number of elements in the table + int threshold; +/** + * Constructs a new, empty hashtable. A default capacity is used. + * Note that the hashtable will automatically grow when it gets full. + */ +public CharArrayCache() { + this(13); +} +/** + * Constructs a new, empty hashtable with the specified initial + * capacity. + * @param initialCapacity int + * the initial number of buckets + */ +public CharArrayCache(int initialCapacity) { + this.elementSize = 0; + this.threshold = (int) (initialCapacity * 0.66f); + this.keyTable = new char[initialCapacity][]; + this.valueTable = new int[initialCapacity]; +} +/** + * Clears the hash table so that it has no more elements in it. + */ +public void clear() { + for (int i = keyTable.length; --i >= 0;) { + keyTable[i] = null; + valueTable[i] = 0; + } + elementSize = 0; +} +/** Returns true if the collection contains an element for the key. + * + * @param key char[] the key that we are looking for + * @return boolean + */ +public boolean containsKey(char[] key) { + int index = hashCodeChar(key); + while (keyTable[index] != null) { + if (CharOperation.equals(keyTable[index], key)) + return true; + index = (index + 1) % keyTable.length; + } + return false; +} +/** Gets the object associated with the specified key in the + * hashtable. + * @param key char[] the specified key + * @return int the element for the key or -1 if the key is not + * defined in the hash table. + */ +public int get(char[] key) { + int index = hashCodeChar(key); + while (keyTable[index] != null) { + if (CharOperation.equals(keyTable[index], key)) + return valueTable[index]; + index = (index + 1) % keyTable.length; + } + return -1; +} +private int hashCodeChar(char[] val) { + int length = val.length; + int hash = 0; + int n = 2; // number of characters skipped + for (int i = 0; i < length; i += n) { + hash += val[i]; + } + return (hash & 0x7FFFFFFF) % keyTable.length; +} +/** + * Puts the specified element into the hashtable, using the specified + * key. The element may be retrieved by doing a get() with the same key. + * The key and the element cannot be null. + * + * @param key Object the specified key in the hashtable + * @param value int the specified element + * @return int the old value of the key, or -1 if it did not have one. + */ +public int put(char[] key, int value) { + int index = hashCodeChar(key); + while (keyTable[index] != null) { + if (CharOperation.equals(keyTable[index], key)) + return valueTable[index] = value; + index = (index + 1) % keyTable.length; + } + keyTable[index] = key; + valueTable[index] = value; + + // assumes the threshold is never equal to the size of the table + if (++elementSize > threshold) + rehash(); + return value; +} +/** + * Rehashes the content of the table into a bigger table. + * This method is called automatically when the hashtable's + * size exceeds the threshold. + */ +private void rehash() { + CharArrayCache newHashtable = new CharArrayCache(keyTable.length * 2); + for (int i = keyTable.length; --i >= 0;) + if (keyTable[i] != null) + newHashtable.put(keyTable[i], valueTable[i]); + + this.keyTable = newHashtable.keyTable; + this.valueTable = newHashtable.valueTable; + this.threshold = newHashtable.threshold; +} +/** Remove the object associated with the specified key in the + * hashtable. + * @param key char[] the specified key + */ +public void remove(char[] key) { + int index = hashCodeChar(key); + while (keyTable[index] != null) { + if (CharOperation.equals(keyTable[index], key)) { + valueTable[index] = 0; + keyTable[index] = null; + return; + } + index = (index + 1) % keyTable.length; + } +} +/** + * Returns the key corresponding to the value. Returns null if the + * receiver doesn't contain the value. + * @param value int the value that we are looking for + * @return Object + */ +public char[] returnKeyFor(int value) { + for (int i = keyTable.length; i-- > 0;) { + if (valueTable[i] == value) { + return keyTable[i]; + } + } + return null; +} +/** + * Returns the number of elements contained in the hashtable. + * + * @return int The size of the table + */ +public int size() { + return elementSize; +} +/** + * Converts to a rather lengthy String. + * + * return String the ascii representation of the receiver + */ +public String toString() { + int max = size(); + StringBuffer buf = new StringBuffer(); + buf.append("{"); //$NON-NLS-1$ + for (int i = 0; i < max; ++i) { + if (keyTable[i] != null) { + buf.append(keyTable[i]).append("->").append(valueTable[i]); //$NON-NLS-1$ + } + if (i < max) { + buf.append(", "); //$NON-NLS-1$ + } + } + buf.append("}"); //$NON-NLS-1$ + return buf.toString(); +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java b/src/java/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java new file mode 100644 index 0000000..4d7a6ef --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java @@ -0,0 +1,5336 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.codegen; + +import org.eclipse.jdt.internal.compiler.*; + +import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.ast.*; +import org.eclipse.jdt.internal.compiler.classfmt.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class CodeStream implements OperatorIds, ClassFileConstants, Opcodes, BaseTypes, TypeConstants, TypeIds { + + public static final boolean DEBUG = false; + + // It will be responsible for the following items. + // -> Tracking Max Stack. + + public int stackMax; // Use Ints to keep from using extra bc when adding + public int stackDepth; // Use Ints to keep from using extra bc when adding + public int maxLocals; + public static final int LABELS_INCREMENT = 5; + public byte[] bCodeStream; + public int pcToSourceMapSize; + public int[] pcToSourceMap = new int[24]; + public int lastEntryPC; // last entry recorded + public int[] lineSeparatorPositions; + public int position; // So when first set can be incremented + public int classFileOffset; + public int startingClassFileOffset; // I need to keep the starting point inside the byte array + public ConstantPool constantPool; // The constant pool used to generate bytecodes that need to store information into the constant pool + public ClassFile classFile; // The current classfile it is associated to. + // local variable attributes output + public static final int LOCALS_INCREMENT = 10; + public LocalVariableBinding[] locals = new LocalVariableBinding[LOCALS_INCREMENT]; + static LocalVariableBinding[] noLocals = new LocalVariableBinding[LOCALS_INCREMENT]; + public LocalVariableBinding[] visibleLocals = new LocalVariableBinding[LOCALS_INCREMENT]; + static LocalVariableBinding[] noVisibleLocals = new LocalVariableBinding[LOCALS_INCREMENT]; + int visibleLocalsCount; + public AbstractMethodDeclaration methodDeclaration; + public ExceptionLabel[] exceptionHandlers = new ExceptionLabel[LABELS_INCREMENT]; + static ExceptionLabel[] noExceptionHandlers = new ExceptionLabel[LABELS_INCREMENT]; + public int exceptionHandlersNumber; + public static FieldBinding[] ImplicitThis = new FieldBinding[] {}; + public boolean generateLineNumberAttributes; + public boolean generateLocalVariableTableAttributes; + public boolean preserveUnusedLocals; + // store all the labels placed at the current position to be able to optimize + // a jump to the next bytecode. + public Label[] labels = new Label[LABELS_INCREMENT]; + static Label[] noLabels = new Label[LABELS_INCREMENT]; + public int countLabels; + public int allLocalsCounter; + public int maxFieldCount; + // to handle goto_w + public boolean wideMode = false; + public static final CompilationResult RESTART_IN_WIDE_MODE = new CompilationResult((char[])null, 0, 0, 0); + +public CodeStream(ClassFile classFile) { + generateLineNumberAttributes = (classFile.produceDebugAttributes & CompilerOptions.Lines) != 0; + generateLocalVariableTableAttributes = (classFile.produceDebugAttributes & CompilerOptions.Vars) != 0; + if (generateLineNumberAttributes) { + lineSeparatorPositions = classFile.referenceBinding.scope.referenceCompilationUnit().compilationResult.lineSeparatorPositions; + } +} +final public void aaload() { + if (DEBUG) System.out.println(position + "\t\taaload"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_aaload; +} +final public void aastore() { + if (DEBUG) System.out.println(position + "\t\taastore"); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 3; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_aastore; +} +final public void aconst_null() { + if (DEBUG) System.out.println(position + "\t\taconst_null"); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) { + stackMax = stackDepth; + } + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_aconst_null; +} +public final void addDefinitelyAssignedVariables(Scope scope, int initStateIndex) { + // Required to fix 1PR0XVS: LFRE:WINNT - Compiler: variable table for method appears incorrect + if (!generateLocalVariableTableAttributes) + return; +/* if (initStateIndex == lastInitStateIndexWhenAddingInits) + return; + lastInitStateIndexWhenAddingInits = initStateIndex; + if (lastInitStateIndexWhenRemovingInits != initStateIndex){ + lastInitStateIndexWhenRemovingInits = -2; // reinitialize remove index + // remove(1)-add(1)-remove(1) -> ignore second remove + // remove(1)-add(2)-remove(1) -> perform second remove + } + +*/ for (int i = 0; i < visibleLocalsCount; i++) { + LocalVariableBinding localBinding = visibleLocals[i]; + if (localBinding != null) { + // Check if the local is definitely assigned + if ((initStateIndex != -1) && isDefinitelyAssigned(scope, initStateIndex, localBinding)) { + if ((localBinding.initializationCount == 0) || (localBinding.initializationPCs[((localBinding.initializationCount - 1) << 1) + 1] != -1)) { + /* There are two cases: + * 1) there is no initialization interval opened ==> add an opened interval + * 2) there is already some initialization intervals but the last one is closed ==> add an opened interval + * An opened interval means that the value at localBinding.initializationPCs[localBinding.initializationCount - 1][1] + * is equals to -1. + * initializationPCs is a collection of pairs of int: + * first value is the startPC and second value is the endPC. -1 one for the last value means that the interval + * is not closed yet. + */ + localBinding.recordInitializationStartPC(position); + } + } + } + } +} +public void addLabel(Label aLabel) { + if (countLabels == labels.length) + System.arraycopy(labels, 0, labels = new Label[countLabels + LABELS_INCREMENT], 0, countLabels); + labels[countLabels++] = aLabel; +} +public void addVisibleLocalVariable(LocalVariableBinding localBinding) { + if (!generateLocalVariableTableAttributes) + return; + + if (visibleLocalsCount >= visibleLocals.length) + System.arraycopy(visibleLocals, 0, visibleLocals = new LocalVariableBinding[visibleLocalsCount * 2], 0, visibleLocalsCount); + visibleLocals[visibleLocalsCount++] = localBinding; +} +final public void aload(int iArg) { + if (DEBUG) System.out.println(position + "\t\taload:"+iArg); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (maxLocals <= iArg) { + maxLocals = iArg + 1; + } + if (iArg > 255) { // Widen + if (classFileOffset + 3 >= bCodeStream.length) { + resizeByteArray(); + } + position += 2; + bCodeStream[classFileOffset++] = OPC_wide; + bCodeStream[classFileOffset++] = OPC_aload; + writeUnsignedShort(iArg); + } else { + // Don't need to use the wide bytecode + if (classFileOffset + 1 >= bCodeStream.length) { + resizeByteArray(); + } + position += 2; + bCodeStream[classFileOffset++] = OPC_aload; + bCodeStream[classFileOffset++] = (byte) iArg; + } +} +final public void aload_0() { + if (DEBUG) System.out.println(position + "\t\taload_0"); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) { + stackMax = stackDepth; + } + if (maxLocals == 0) { + maxLocals = 1; + } + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_aload_0; +} +final public void aload_1() { + if (DEBUG) System.out.println(position + "\t\taload_1"); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (maxLocals <= 1) { + maxLocals = 2; + } + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_aload_1; +} +final public void aload_2() { + if (DEBUG) System.out.println(position + "\t\taload_2"); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (maxLocals <= 2) { + maxLocals = 3; + } + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_aload_2; +} +final public void aload_3() { + if (DEBUG) System.out.println(position + "\t\taload_3"); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (maxLocals <= 3) { + maxLocals = 4; + } + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_aload_3; +} +public final void anewarray(TypeBinding typeBinding) { + if (DEBUG) System.out.println(position + "\t\tanewarray: " + typeBinding); //$NON-NLS-1$ + countLabels = 0; + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_anewarray; + writeUnsignedShort(constantPool.literalIndex(typeBinding)); +} +final public void areturn() { + if (DEBUG) System.out.println(position + "\t\tareturn"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + // the stackDepth should be equal to 0 + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_areturn; +} +public void arrayAt(int typeBindingID) { + switch (typeBindingID) { + case T_int : + this.iaload(); + break; + case T_byte : + case T_boolean : + this.baload(); + break; + case T_short : + this.saload(); + break; + case T_char : + this.caload(); + break; + case T_long : + this.laload(); + break; + case T_float : + this.faload(); + break; + case T_double : + this.daload(); + break; + default : + this.aaload(); + } +} +public void arrayAtPut(int elementTypeID, boolean valueRequired) { + switch (elementTypeID) { + case T_int : + if (valueRequired) + dup_x2(); + iastore(); + break; + case T_byte : + case T_boolean : + if (valueRequired) + dup_x2(); + bastore(); + break; + case T_short : + if (valueRequired) + dup_x2(); + sastore(); + break; + case T_char : + if (valueRequired) + dup_x2(); + castore(); + break; + case T_long : + if (valueRequired) + dup2_x2(); + lastore(); + break; + case T_float : + if (valueRequired) + dup_x2(); + fastore(); + break; + case T_double : + if (valueRequired) + dup2_x2(); + dastore(); + break; + default : + if (valueRequired) + dup_x2(); + aastore(); + } +} +final public void arraylength() { + if (DEBUG) System.out.println(position + "\t\tarraylength"); //$NON-NLS-1$ + countLabels = 0; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_arraylength; +} +final public void astore(int iArg) { + if (DEBUG) System.out.println(position + "\t\tastore:"+iArg); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (maxLocals <= iArg) { + maxLocals = iArg + 1; + } + if (iArg > 255) { // Widen + if (classFileOffset + 3 >= bCodeStream.length) { + resizeByteArray(); + } + position+=2; + bCodeStream[classFileOffset++] = OPC_wide; + bCodeStream[classFileOffset++] = OPC_astore; + writeUnsignedShort(iArg); + } else { + if (classFileOffset + 1 >= bCodeStream.length) { + resizeByteArray(); + } + position+=2; + bCodeStream[classFileOffset++] = OPC_astore; + bCodeStream[classFileOffset++] = (byte) iArg; + } +} +final public void astore_0() { + if (DEBUG) System.out.println(position + "\t\tastore_0"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (maxLocals == 0) { + maxLocals = 1; + } + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_astore_0; +} +final public void astore_1() { + if (DEBUG) System.out.println(position + "\t\tastore_1"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (maxLocals <= 1) { + maxLocals = 2; + } + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_astore_1; +} +final public void astore_2() { + if (DEBUG) System.out.println(position + "\t\tastore_2"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (maxLocals <= 2) { + maxLocals = 3; + } + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_astore_2; +} +final public void astore_3() { + if (DEBUG) System.out.println(position + "\t\tastore_3"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (maxLocals <= 3) { + maxLocals = 4; + } + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_astore_3; +} +final public void athrow() { + if (DEBUG) System.out.println(position + "\t\tathrow"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_athrow; +} +final public void baload() { + if (DEBUG) System.out.println(position + "\t\tbaload"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_baload; +} +final public void bastore() { + if (DEBUG) System.out.println(position + "\t\tbastore"); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 3; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_bastore; +} +final public void bipush(byte b) { + if (DEBUG) System.out.println(position + "\t\tbipush "+b); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset + 1 >= bCodeStream.length) { + resizeByteArray(); + } + position += 2; + bCodeStream[classFileOffset++] = OPC_bipush; + bCodeStream[classFileOffset++] = b; +} +final public void caload() { + if (DEBUG) System.out.println(position + "\t\tcaload"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_caload; +} +final public void castore() { + if (DEBUG) System.out.println(position + "\t\tcastore"); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 3; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_castore; +} +public final void checkcast(TypeBinding typeBinding) { + if (DEBUG) System.out.println(position + "\t\tcheckcast:"+typeBinding); //$NON-NLS-1$ + countLabels = 0; + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_checkcast; + writeUnsignedShort(constantPool.literalIndex(typeBinding)); +} +final public void d2f() { + if (DEBUG) System.out.println(position + "\t\td2f"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_d2f; +} +final public void d2i() { + if (DEBUG) System.out.println(position + "\t\td2i"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_d2i; +} +final public void d2l() { + if (DEBUG) System.out.println(position + "\t\td2l"); //$NON-NLS-1$ + countLabels = 0; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_d2l; +} +final public void dadd() { + if (DEBUG) System.out.println(position + "\t\tdadd"); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 2; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_dadd; +} +final public void daload() { + if (DEBUG) System.out.println(position + "\t\tdaload"); //$NON-NLS-1$ + countLabels = 0; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_daload; +} +final public void dastore() { + if (DEBUG) System.out.println(position + "\t\tdastore"); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 4; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_dastore; +} +final public void dcmpg() { + if (DEBUG) System.out.println(position + "\t\tdcmpg"); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 3; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_dcmpg; +} +final public void dcmpl() { + if (DEBUG) System.out.println(position + "\t\tdcmpl"); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 3; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_dcmpl; +} +final public void dconst_0() { + if (DEBUG) System.out.println(position + "\t\tdconst_0"); //$NON-NLS-1$ + countLabels = 0; + stackDepth += 2; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_dconst_0; +} +final public void dconst_1() { + if (DEBUG) System.out.println(position + "\t\tdconst_1"); //$NON-NLS-1$ + countLabels = 0; + stackDepth += 2; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_dconst_1; +} +final public void ddiv() { + if (DEBUG) System.out.println(position + "\t\tddiv"); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 2; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_ddiv; +} +public void decrStackSize(int offset) { + stackDepth -= offset; +} +final public void dload(int iArg) { + if (DEBUG) System.out.println(position + "\t\tdload:"+iArg); //$NON-NLS-1$ + countLabels = 0; + stackDepth += 2; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (maxLocals < iArg + 2) { + maxLocals = iArg + 2; // + 2 because it is a double + } + if (iArg > 255) { // Widen + if (classFileOffset + 3 >= bCodeStream.length) { + resizeByteArray(); + } + position += 2; + bCodeStream[classFileOffset++] = OPC_wide; + bCodeStream[classFileOffset++] = OPC_dload; + writeUnsignedShort(iArg); + } else { + // Don't need to use the wide bytecode + if (classFileOffset + 1 >= bCodeStream.length) { + resizeByteArray(); + } + position += 2; + bCodeStream[classFileOffset++] = OPC_dload; + bCodeStream[classFileOffset++] = (byte) iArg; + } +} +final public void dload_0() { + if (DEBUG) System.out.println(position + "\t\tdload_0"); //$NON-NLS-1$ + countLabels = 0; + stackDepth += 2; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (maxLocals < 2) { + maxLocals = 2; + } + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_dload_0; +} +final public void dload_1() { + if (DEBUG) System.out.println(position + "\t\tdload_1"); //$NON-NLS-1$ + countLabels = 0; + stackDepth += 2; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (maxLocals < 3) { + maxLocals = 3; + } + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_dload_1; +} +final public void dload_2() { + if (DEBUG) System.out.println(position + "\t\tdload_2"); //$NON-NLS-1$ + countLabels = 0; + stackDepth += 2; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (maxLocals < 4) { + maxLocals = 4; + } + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_dload_2; +} +final public void dload_3() { + if (DEBUG) System.out.println(position + "\t\tdload_3"); //$NON-NLS-1$ + countLabels = 0; + stackDepth += 2; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (maxLocals < 5) { + maxLocals = 5; + } + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_dload_3; +} +final public void dmul() { + if (DEBUG) System.out.println(position + "\t\tdmul"); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 2; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_dmul; +} +final public void dneg() { + if (DEBUG) System.out.println(position + "\t\tdneg"); //$NON-NLS-1$ + countLabels = 0; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_dneg; +} +final public void drem() { + if (DEBUG) System.out.println(position + "\t\tdrem"); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 2; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_drem; +} +final public void dreturn() { + if (DEBUG) System.out.println(position + "\t\tdreturn"); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 2; + // the stackDepth should be equal to 0 + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_dreturn; +} +final public void dstore(int iArg) { + if (DEBUG) System.out.println(position + "\t\tdstore:"+iArg); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 2; + if (maxLocals <= iArg + 1) { + maxLocals = iArg + 2; + } + if (iArg > 255) { // Widen + if (classFileOffset + 3 >= bCodeStream.length) { + resizeByteArray(); + } + position += 2; + bCodeStream[classFileOffset++] = OPC_wide; + bCodeStream[classFileOffset++] = OPC_dstore; + writeUnsignedShort(iArg); + } else { + if (classFileOffset + 1 >= bCodeStream.length) { + resizeByteArray(); + } + position += 2; + bCodeStream[classFileOffset++] = OPC_dstore; + bCodeStream[classFileOffset++] = (byte) iArg; + } +} +final public void dstore_0() { + if (DEBUG) System.out.println(position + "\t\tdstore_0"); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 2; + if (maxLocals < 2) { + maxLocals = 2; + } + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_dstore_0; +} +final public void dstore_1() { + if (DEBUG) System.out.println(position + "\t\tdstore_1"); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 2; + if (maxLocals < 3) { + maxLocals = 3; + } + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_dstore_1; +} +final public void dstore_2() { + if (DEBUG) System.out.println(position + "\t\tdstore_2"); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 2; + if (maxLocals < 4) { + maxLocals = 4; + } + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_dstore_2; +} +final public void dstore_3() { + if (DEBUG) System.out.println(position + "\t\tdstore_3"); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 2; + if (maxLocals < 5) { + maxLocals = 5; + } + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_dstore_3; +} +final public void dsub() { + if (DEBUG) System.out.println(position + "\t\tdsub"); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 2; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_dsub; +} +final public void dup() { + if (DEBUG) System.out.println(position + "\t\tdup"); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) { + stackMax = stackDepth; + } + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_dup; +} +final public void dup_x1() { + if (DEBUG) System.out.println(position + "\t\tdup_x1"); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_dup_x1; +} +final public void dup_x2() { + if (DEBUG) System.out.println(position + "\t\tdup_x2"); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_dup_x2; +} +final public void dup2() { + if (DEBUG) System.out.println(position + "\t\tdup2"); //$NON-NLS-1$ + countLabels = 0; + stackDepth += 2; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_dup2; +} +final public void dup2_x1() { + if (DEBUG) System.out.println(position + "\t\tdup2_x1"); //$NON-NLS-1$ + countLabels = 0; + stackDepth += 2; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_dup2_x1; +} +final public void dup2_x2() { + if (DEBUG) System.out.println(position + "\t\tdup2_x2"); //$NON-NLS-1$ + countLabels = 0; + stackDepth += 2; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_dup2_x2; +} +public void exitUserScope(BlockScope blockScope) { + // mark all the scope's locals as loosing their definite assignment + + if (!generateLocalVariableTableAttributes) + return; + for (int i = 0; i < visibleLocalsCount; i++) { + LocalVariableBinding visibleLocal = visibleLocals[i]; + if ((visibleLocal != null) && (visibleLocal.declaringScope == blockScope)) { + // there maybe some some preserved locals never initialized + if (visibleLocal.initializationCount > 0){ + visibleLocals[i].recordInitializationEndPC(position); + } + visibleLocals[i] = null; // this variable is no longer visible afterwards + } + } +} +final public void f2d() { + if (DEBUG) System.out.println(position + "\t\tf2d"); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_f2d; +} +final public void f2i() { + if (DEBUG) System.out.println(position + "\t\tf2i"); //$NON-NLS-1$ + countLabels = 0; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_f2i; +} +final public void f2l() { + if (DEBUG) System.out.println(position + "\t\tf2l"); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_f2l; +} +final public void fadd() { + if (DEBUG) System.out.println(position + "\t\tfadd"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_fadd; +} +final public void faload() { + if (DEBUG) System.out.println(position + "\t\tfaload"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_faload; +} +final public void fastore() { + if (DEBUG) System.out.println(position + "\t\tfaload"); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 3; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_fastore; +} +final public void fcmpg() { + if (DEBUG) System.out.println(position + "\t\tfcmpg"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_fcmpg; +} +final public void fcmpl() { + if (DEBUG) System.out.println(position + "\t\tfcmpl"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_fcmpl; +} +final public void fconst_0() { + if (DEBUG) System.out.println(position + "\t\tfconst_0"); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_fconst_0; +} +final public void fconst_1() { + if (DEBUG) System.out.println(position + "\t\tfconst_1"); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_fconst_1; +} +final public void fconst_2() { + if (DEBUG) System.out.println(position + "\t\tfconst_2"); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_fconst_2; +} +final public void fdiv() { + if (DEBUG) System.out.println(position + "\t\tfdiv"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_fdiv; +} +final public void fload(int iArg) { + if (DEBUG) System.out.println(position + "\t\tfload:"+iArg); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (maxLocals <= iArg) { + maxLocals = iArg + 1; + } + if (stackDepth > stackMax) + stackMax = stackDepth; + if (iArg > 255) { // Widen + if (classFileOffset + 3 >= bCodeStream.length) { + resizeByteArray(); + } + position += 2; + bCodeStream[classFileOffset++] = OPC_wide; + bCodeStream[classFileOffset++] = OPC_fload; + writeUnsignedShort(iArg); + } else { + if (classFileOffset + 1 >= bCodeStream.length) { + resizeByteArray(); + } + position += 2; + bCodeStream[classFileOffset++] = OPC_fload; + bCodeStream[classFileOffset++] = (byte) iArg; + } +} +final public void fload_0() { + if (DEBUG) System.out.println(position + "\t\tfload_0"); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (maxLocals == 0) { + maxLocals = 1; + } + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_fload_0; +} +final public void fload_1() { + if (DEBUG) System.out.println(position + "\t\tfload_1"); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (maxLocals <= 1) { + maxLocals = 2; + } + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_fload_1; +} +final public void fload_2() { + if (DEBUG) System.out.println(position + "\t\tfload_2"); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (maxLocals <= 2) { + maxLocals = 3; + } + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_fload_2; +} +final public void fload_3() { + if (DEBUG) System.out.println(position + "\t\tfload_3"); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (maxLocals <= 3) { + maxLocals = 4; + } + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_fload_3; +} +final public void fmul() { + if (DEBUG) System.out.println(position + "\t\tfmul"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_fmul; +} +final public void fneg() { + if (DEBUG) System.out.println(position + "\t\tfneg"); //$NON-NLS-1$ + countLabels = 0; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_fneg; +} +final public void frem() { + if (DEBUG) System.out.println(position + "\t\tfrem"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_frem; +} +final public void freturn() { + if (DEBUG) System.out.println(position + "\t\tfreturn"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + // the stackDepth should be equal to 0 + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_freturn; +} +final public void fstore(int iArg) { + if (DEBUG) System.out.println(position + "\t\tfstore:"+iArg); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (maxLocals <= iArg) { + maxLocals = iArg + 1; + } + if (iArg > 255) { // Widen + if (classFileOffset + 3 >= bCodeStream.length) { + resizeByteArray(); + } + position += 2; + bCodeStream[classFileOffset++] = OPC_wide; + bCodeStream[classFileOffset++] = OPC_fstore; + writeUnsignedShort(iArg); + } else { + if (classFileOffset + 1 >= bCodeStream.length) { + resizeByteArray(); + } + position += 2; + bCodeStream[classFileOffset++] = OPC_fstore; + bCodeStream[classFileOffset++] = (byte) iArg; + } +} +final public void fstore_0() { + if (DEBUG) System.out.println(position + "\t\tfstore_0"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (maxLocals == 0) { + maxLocals = 1; + } + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_fstore_0; +} +final public void fstore_1() { + if (DEBUG) System.out.println(position + "\t\tfstore_1"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (maxLocals <= 1) { + maxLocals = 2; + } + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_fstore_1; +} +final public void fstore_2() { + if (DEBUG) System.out.println(position + "\t\tfstore_2"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (maxLocals <= 2) { + maxLocals = 3; + } + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_fstore_2; +} +final public void fstore_3() { + if (DEBUG) System.out.println(position + "\t\tfstore_3"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (maxLocals <= 3) { + maxLocals = 4; + } + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_fstore_3; +} +final public void fsub() { + if (DEBUG) System.out.println(position + "\t\tfsub"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_fsub; +} +/** + * Macro for building a class descriptor object + */ +public void generateClassLiteralAccessForType(TypeBinding accessedType, FieldBinding syntheticFieldBinding) { + Label endLabel; + ExceptionLabel anyExceptionHandler; + int saveStackSize; + if (accessedType.isBaseType() && accessedType != NullBinding) { + this.getTYPE(accessedType.id); + return; + } + endLabel = new Label(this); + + if (syntheticFieldBinding != null) { // non interface case + this.getstatic(syntheticFieldBinding); + this.dup(); + this.ifnonnull(endLabel); + this.pop(); + } + + /* Macro for building a class descriptor object... using or not a field cache to store it into... + this sequence is responsible for building the actual class descriptor. + + If the fieldCache is set, then it is supposed to be the body of a synthetic access method + factoring the actual descriptor creation out of the invocation site (saving space). + If the fieldCache is nil, then we are dumping the bytecode on the invocation site, since + we have no way to get a hand on the field cache to do better. */ + + + // Wrap the code in an exception handler to convert a ClassNotFoundException into a NoClassDefError + + anyExceptionHandler = new ExceptionLabel(this, BaseTypes.NullBinding /* represents ClassNotFoundException*/); + this.ldc(accessedType == BaseTypes.NullBinding ? "java.lang.Object" : String.valueOf(accessedType.constantPoolName()).replace('/', '.')); //$NON-NLS-1$ + this.invokeClassForName(); + + /* See https://bugs.eclipse.org/bugs/show_bug.cgi?id=37565 + if (accessedType == BaseTypes.NullBinding) { + this.ldc("java.lang.Object"); //$NON-NLS-1$ + } else if (accessedType.isArrayType()) { + this.ldc(String.valueOf(accessedType.constantPoolName()).replace('/', '.')); + } else { + // we make it an array type (to avoid class initialization) + this.ldc("[L" + String.valueOf(accessedType.constantPoolName()).replace('/', '.') + ";"); //$NON-NLS-1$//$NON-NLS-2$ + } + this.invokeClassForName(); + if (!accessedType.isArrayType()) { // extract the component type, which doesn't initialize the class + this.invokeJavaLangClassGetComponentType(); + } + */ + /* We need to protect the runtime code from binary inconsistencies + in case the accessedType is missing, the ClassNotFoundException has to be converted + into a NoClassDefError(old ex message), we thus need to build an exception handler for this one. */ + anyExceptionHandler.placeEnd(); + + if (syntheticFieldBinding != null) { // non interface case + this.dup(); + this.putstatic(syntheticFieldBinding); + } + this.goto_(endLabel); + + + // Generate the body of the exception handler + saveStackSize = stackDepth; + stackDepth = 1; + /* ClassNotFoundException on stack -- the class literal could be doing more things + on the stack, which means that the stack may not be empty at this point in the + above code gen. So we save its state and restart it from 1. */ + + anyExceptionHandler.place(); + + // Transform the current exception, and repush and throw a + // NoClassDefFoundError(ClassNotFound.getMessage()) + + this.newNoClassDefFoundError(); + this.dup_x1(); + this.swap(); + + // Retrieve the message from the old exception + this.invokeThrowableGetMessage(); + + // Send the constructor taking a message string as an argument + this.invokeNoClassDefFoundErrorStringConstructor(); + this.athrow(); + endLabel.place(); + stackDepth = saveStackSize; +} +/** + * This method generates the code attribute bytecode + */ +final public void generateCodeAttributeForProblemMethod(String problemMessage) { + newJavaLangError(); + dup(); + ldc(problemMessage); + invokeJavaLangErrorConstructor(); + athrow(); +} +public void generateConstant(Constant constant, int implicitConversionCode) { + int targetTypeID = implicitConversionCode >> 4; + switch (targetTypeID) { + case T_boolean : + generateInlinedValue(constant.booleanValue()); + break; + case T_char : + generateInlinedValue(constant.charValue()); + break; + case T_byte : + generateInlinedValue(constant.byteValue()); + break; + case T_short : + generateInlinedValue(constant.shortValue()); + break; + case T_int : + generateInlinedValue(constant.intValue()); + break; + case T_long : + generateInlinedValue(constant.longValue()); + break; + case T_float : + generateInlinedValue(constant.floatValue()); + break; + case T_double : + generateInlinedValue(constant.doubleValue()); + break; + default : //String or Object + ldc(constant.stringValue()); + } +} +/** + * @param implicitConversionCode int + */ +public void generateImplicitConversion(int implicitConversionCode) { + switch (implicitConversionCode) { + case Float2Char : + this.f2i(); + this.i2c(); + break; + case Double2Char : + this.d2i(); + this.i2c(); + break; + case Int2Char : + case Short2Char : + case Byte2Char : + this.i2c(); + break; + case Long2Char : + this.l2i(); + this.i2c(); + break; + case Char2Float : + case Short2Float : + case Int2Float : + case Byte2Float : + this.i2f(); + break; + case Double2Float : + this.d2f(); + break; + case Long2Float : + this.l2f(); + break; + case Float2Byte : + this.f2i(); + this.i2b(); + break; + case Double2Byte : + this.d2i(); + this.i2b(); + break; + case Int2Byte : + case Short2Byte : + case Char2Byte : + this.i2b(); + break; + case Long2Byte : + this.l2i(); + this.i2b(); + break; + case Byte2Double : + case Char2Double : + case Short2Double : + case Int2Double : + this.i2d(); + break; + case Float2Double : + this.f2d(); + break; + case Long2Double : + this.l2d(); + break; + case Byte2Short : + case Char2Short : + case Int2Short : + this.i2s(); + break; + case Double2Short : + this.d2i(); + this.i2s(); + break; + case Long2Short : + this.l2i(); + this.i2s(); + break; + case Float2Short : + this.f2i(); + this.i2s(); + break; + case Double2Int : + this.d2i(); + break; + case Float2Int : + this.f2i(); + break; + case Long2Int : + this.l2i(); + break; + case Int2Long : + case Char2Long : + case Byte2Long : + case Short2Long : + this.i2l(); + break; + case Double2Long : + this.d2l(); + break; + case Float2Long : + this.f2l(); + } +} +public void generateInlinedValue(byte inlinedValue) { + switch (inlinedValue) { + case -1 : + this.iconst_m1(); + break; + case 0 : + this.iconst_0(); + break; + case 1 : + this.iconst_1(); + break; + case 2 : + this.iconst_2(); + break; + case 3 : + this.iconst_3(); + break; + case 4 : + this.iconst_4(); + break; + case 5 : + this.iconst_5(); + break; + default : + if ((-128 <= inlinedValue) && (inlinedValue <= 127)) { + this.bipush(inlinedValue); + return; + } + } +} +public void generateInlinedValue(char inlinedValue) { + switch (inlinedValue) { + case 0 : + this.iconst_0(); + break; + case 1 : + this.iconst_1(); + break; + case 2 : + this.iconst_2(); + break; + case 3 : + this.iconst_3(); + break; + case 4 : + this.iconst_4(); + break; + case 5 : + this.iconst_5(); + break; + default : + if ((6 <= inlinedValue) && (inlinedValue <= 127)) { + this.bipush((byte) inlinedValue); + return; + } + if ((128 <= inlinedValue) && (inlinedValue <= 32767)) { + this.sipush(inlinedValue); + return; + } + this.ldc(inlinedValue); + } +} +public void generateInlinedValue(double inlinedValue) { + if (inlinedValue == 0.0) { + if (Double.doubleToLongBits(inlinedValue) != 0L) + this.ldc2_w(inlinedValue); + else + this.dconst_0(); + return; + } + if (inlinedValue == 1.0) { + this.dconst_1(); + return; + } + this.ldc2_w(inlinedValue); +} +public void generateInlinedValue(float inlinedValue) { + if (inlinedValue == 0.0f) { + if (Float.floatToIntBits(inlinedValue) != 0) + this.ldc(inlinedValue); + else + this.fconst_0(); + return; + } + if (inlinedValue == 1.0f) { + this.fconst_1(); + return; + } + if (inlinedValue == 2.0f) { + this.fconst_2(); + return; + } + this.ldc(inlinedValue); +} +public void generateInlinedValue(int inlinedValue) { + switch (inlinedValue) { + case -1 : + this.iconst_m1(); + break; + case 0 : + this.iconst_0(); + break; + case 1 : + this.iconst_1(); + break; + case 2 : + this.iconst_2(); + break; + case 3 : + this.iconst_3(); + break; + case 4 : + this.iconst_4(); + break; + case 5 : + this.iconst_5(); + break; + default : + if ((-128 <= inlinedValue) && (inlinedValue <= 127)) { + this.bipush((byte) inlinedValue); + return; + } + if ((-32768 <= inlinedValue) && (inlinedValue <= 32767)) { + this.sipush(inlinedValue); + return; + } + this.ldc(inlinedValue); + } +} +public void generateInlinedValue(long inlinedValue) { + if (inlinedValue == 0) { + this.lconst_0(); + return; + } + if (inlinedValue == 1) { + this.lconst_1(); + return; + } + this.ldc2_w(inlinedValue); +} +public void generateInlinedValue(short inlinedValue) { + switch (inlinedValue) { + case -1 : + this.iconst_m1(); + break; + case 0 : + this.iconst_0(); + break; + case 1 : + this.iconst_1(); + break; + case 2 : + this.iconst_2(); + break; + case 3 : + this.iconst_3(); + break; + case 4 : + this.iconst_4(); + break; + case 5 : + this.iconst_5(); + break; + default : + if ((-128 <= inlinedValue) && (inlinedValue <= 127)) { + this.bipush((byte) inlinedValue); + return; + } + this.sipush(inlinedValue); + } +} +public void generateInlinedValue(boolean inlinedValue) { + if (inlinedValue) + this.iconst_1(); + else + this.iconst_0(); +} +public void generateOuterAccess(Object[] mappingSequence, ASTNode invocationSite, Binding target, Scope scope) { + if (mappingSequence == null) { + if (target instanceof LocalVariableBinding) { + scope.problemReporter().needImplementation(); //TODO (philippe) should improve local emulation failure reporting + } else { + scope.problemReporter().noSuchEnclosingInstance((ReferenceBinding)target, invocationSite, false); + } + return; + } + if (mappingSequence == BlockScope.NoEnclosingInstanceInConstructorCall) { + scope.problemReporter().noSuchEnclosingInstance((ReferenceBinding)target, invocationSite, true); + return; + } else if (mappingSequence == BlockScope.NoEnclosingInstanceInStaticContext) { + scope.problemReporter().noSuchEnclosingInstance((ReferenceBinding)target, invocationSite, false); + return; + } + + if (mappingSequence == BlockScope.EmulationPathToImplicitThis) { + this.aload_0(); + return; + } else if (mappingSequence[0] instanceof FieldBinding) { + FieldBinding fieldBinding = (FieldBinding) mappingSequence[0]; + this.aload_0(); + this.getfield(fieldBinding); + } else { + load((LocalVariableBinding) mappingSequence[0]); + } + for (int i = 1, length = mappingSequence.length; i < length; i++) { + if (mappingSequence[i] instanceof FieldBinding) { + FieldBinding fieldBinding = (FieldBinding) mappingSequence[i]; + this.getfield(fieldBinding); + } else { + this.invokestatic((MethodBinding) mappingSequence[i]); + } + } +} + +/** + * The equivalent code performs a string conversion: + * + * @param blockScope the given blockScope + * @param oper1 the first expression + * @param oper2 the second expression + */ +public void generateStringAppend(BlockScope blockScope, Expression oper1, Expression oper2) { + int pc; + if (oper1 == null) { + /* Operand is already on the stack, and maybe nil: + note type1 is always to java.lang.String here.*/ + this.newStringBuffer(); + this.dup_x1(); + this.swap(); + // If argument is reference type, need to transform it + // into a string (handles null case) + this.invokeStringValueOf(T_Object); + this.invokeStringBufferStringConstructor(); + } else { + pc = position; + oper1.generateOptimizedStringBufferCreation(blockScope, this, oper1.implicitConversion & 0xF); + this.recordPositionsFrom(pc, oper1.sourceStart); + } + pc = position; + oper2.generateOptimizedStringBuffer(blockScope, this, oper2.implicitConversion & 0xF); + this.recordPositionsFrom(pc, oper2.sourceStart); + this.invokeStringBufferToString(); +} +/** + * Code responsible to generate the suitable code to supply values for the synthetic enclosing + * instance arguments of a constructor invocation of a nested type. + */ +public void generateSyntheticEnclosingInstanceValues( + BlockScope currentScope, + ReferenceBinding targetType, + Expression enclosingInstance, + ASTNode invocationSite) { + + // supplying enclosing instance for the anonymous type's superclass + ReferenceBinding checkedTargetType = targetType.isAnonymousType() ? targetType.superclass() : targetType; + boolean hasExtraEnclosingInstance = enclosingInstance != null; + if (hasExtraEnclosingInstance + && (!checkedTargetType.isNestedType() || checkedTargetType.isStatic())) { + currentScope.problemReporter().unnecessaryEnclosingInstanceSpecification(enclosingInstance, checkedTargetType); + return; + } + + // perform some emulation work in case there is some and we are inside a local type only + ReferenceBinding[] syntheticArgumentTypes; + if ((syntheticArgumentTypes = targetType.syntheticEnclosingInstanceTypes()) != null) { + + ReferenceBinding targetEnclosingType = checkedTargetType.enclosingType(); + boolean complyTo14 = currentScope.environment().options.complianceLevel >= ClassFileConstants.JDK1_4; + // deny access to enclosing instance argument for allocation and super constructor call (if 1.4) + boolean ignoreEnclosingArgInConstructorCall = invocationSite instanceof AllocationExpression + || (complyTo14 && ((invocationSite instanceof ExplicitConstructorCall && ((ExplicitConstructorCall)invocationSite).isSuperAccess()))); + + for (int i = 0, max = syntheticArgumentTypes.length; i < max; i++) { + ReferenceBinding syntheticArgType = syntheticArgumentTypes[i]; + if (hasExtraEnclosingInstance && syntheticArgType == targetEnclosingType) { + hasExtraEnclosingInstance = false; + enclosingInstance.generateCode(currentScope, this, true); + if (complyTo14){ + dup(); + invokeObjectGetClass(); // will perform null check + pop(); + } + } else { + Object[] emulationPath = currentScope.getEmulationPath( + syntheticArgType, + false /*not only exact match (that is, allow compatible)*/, + ignoreEnclosingArgInConstructorCall); + this.generateOuterAccess(emulationPath, invocationSite, syntheticArgType, currentScope); + } + } + if (hasExtraEnclosingInstance){ + currentScope.problemReporter().unnecessaryEnclosingInstanceSpecification(enclosingInstance, checkedTargetType); + } + } +} + +/** + * Code responsible to generate the suitable code to supply values for the synthetic outer local + * variable arguments of a constructor invocation of a nested type. + * (bug 26122) - synthetic values for outer locals must be passed after user arguments, e.g. new X(i = 1){} + */ +public void generateSyntheticOuterArgumentValues(BlockScope currentScope, ReferenceBinding targetType, ASTNode invocationSite) { + + // generate the synthetic outer arguments then + SyntheticArgumentBinding syntheticArguments[]; + if ((syntheticArguments = targetType.syntheticOuterLocalVariables()) != null) { + for (int i = 0, max = syntheticArguments.length; i < max; i++) { + LocalVariableBinding targetVariable = syntheticArguments[i].actualOuterLocalVariable; + VariableBinding[] emulationPath = currentScope.getEmulationPath(targetVariable); + this.generateOuterAccess(emulationPath, invocationSite, targetVariable, currentScope); + } + } +} + +/** + * @param accessBinding the access method binding to generate + */ +public void generateSyntheticBodyForConstructorAccess(SyntheticAccessMethodBinding accessBinding) { + + initializeMaxLocals(accessBinding); + + MethodBinding constructorBinding = accessBinding.targetMethod; + TypeBinding[] parameters = constructorBinding.parameters; + int length = parameters.length; + int resolvedPosition = 1; + this.aload_0(); + if (constructorBinding.declaringClass.isNestedType()) { + NestedTypeBinding nestedType = (NestedTypeBinding) constructorBinding.declaringClass; + SyntheticArgumentBinding[] syntheticArguments = nestedType.syntheticEnclosingInstances(); + for (int i = 0; i < (syntheticArguments == null ? 0 : syntheticArguments.length); i++) { + TypeBinding type; + load((type = syntheticArguments[i].type), resolvedPosition); + if ((type == DoubleBinding) || (type == LongBinding)) + resolvedPosition += 2; + else + resolvedPosition++; + } + } + for (int i = 0; i < length; i++) { + load(parameters[i], resolvedPosition); + if ((parameters[i] == DoubleBinding) || (parameters[i] == LongBinding)) + resolvedPosition += 2; + else + resolvedPosition++; + } + + if (constructorBinding.declaringClass.isNestedType()) { + NestedTypeBinding nestedType = (NestedTypeBinding) constructorBinding.declaringClass; + SyntheticArgumentBinding[] syntheticArguments = nestedType.syntheticOuterLocalVariables(); + for (int i = 0; i < (syntheticArguments == null ? 0 : syntheticArguments.length); i++) { + TypeBinding type; + load((type = syntheticArguments[i].type), resolvedPosition); + if ((type == DoubleBinding) || (type == LongBinding)) + resolvedPosition += 2; + else + resolvedPosition++; + } + } + this.invokespecial(constructorBinding); + this.return_(); +} +public void generateSyntheticBodyForFieldReadAccess(SyntheticAccessMethodBinding accessBinding) { + initializeMaxLocals(accessBinding); + FieldBinding fieldBinding = accessBinding.targetReadField; + TypeBinding type; + if (fieldBinding.isStatic()) + this.getstatic(fieldBinding); + else { + this.aload_0(); + this.getfield(fieldBinding); + } + if ((type = fieldBinding.type).isBaseType()) { + if (type == IntBinding) + this.ireturn(); + else + if (type == FloatBinding) + this.freturn(); + else + if (type == LongBinding) + this.lreturn(); + else + if (type == DoubleBinding) + this.dreturn(); + else + this.ireturn(); + } else + this.areturn(); +} +public void generateSyntheticBodyForFieldWriteAccess(SyntheticAccessMethodBinding accessBinding) { + initializeMaxLocals(accessBinding); + FieldBinding fieldBinding = accessBinding.targetWriteField; + if (fieldBinding.isStatic()) { + load(fieldBinding.type, 0); + this.putstatic(fieldBinding); + } else { + this.aload_0(); + load(fieldBinding.type, 1); + this.putfield(fieldBinding); + } + this.return_(); +} +public void generateSyntheticBodyForMethodAccess(SyntheticAccessMethodBinding accessBinding) { + + initializeMaxLocals(accessBinding); + MethodBinding methodBinding = accessBinding.targetMethod; + TypeBinding[] parameters = methodBinding.parameters; + int length = parameters.length; + int resolvedPosition; + if (methodBinding.isStatic()) + resolvedPosition = 0; + else { + this.aload_0(); + resolvedPosition = 1; + } + for (int i = 0; i < length; i++) { + load(parameters[i], resolvedPosition); + if ((parameters[i] == DoubleBinding) || (parameters[i] == LongBinding)) + resolvedPosition += 2; + else + resolvedPosition++; + } + TypeBinding type; + if (methodBinding.isStatic()) + this.invokestatic(methodBinding); + else { + if (methodBinding.isConstructor() + || methodBinding.isPrivate() + // qualified super "X.super.foo()" targets methods from superclass + || accessBinding.accessType == SyntheticAccessMethodBinding.SuperMethodAccess){ + this.invokespecial(methodBinding); + } else { + if (methodBinding.declaringClass.isInterface()){ + this.invokeinterface(methodBinding); + } else { + this.invokevirtual(methodBinding); + } + } + } + if ((type = methodBinding.returnType).isBaseType()) + if (type == VoidBinding) + this.return_(); + else + if (type == IntBinding) + this.ireturn(); + else + if (type == FloatBinding) + this.freturn(); + else + if (type == LongBinding) + this.lreturn(); + else + if (type == DoubleBinding) + this.dreturn(); + else + this.ireturn(); + else + this.areturn(); +} +final public byte[] getContents() { + byte[] contents; + System.arraycopy(bCodeStream, 0, contents = new byte[position], 0, position); + return contents; +} +final public void getfield(FieldBinding fieldBinding) { + if (DEBUG) System.out.println(position + "\t\tgetfield:"+fieldBinding); //$NON-NLS-1$ + countLabels = 0; + if ((fieldBinding.type.id == T_double) || (fieldBinding.type.id == T_long)) { + if (++stackDepth > stackMax) + stackMax = stackDepth; + } + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_getfield; + writeUnsignedShort(constantPool.literalIndex(fieldBinding)); +} +final public void getstatic(FieldBinding fieldBinding) { + if (DEBUG) System.out.println(position + "\t\tgetstatic:"+fieldBinding); //$NON-NLS-1$ + countLabels = 0; + if ((fieldBinding.type.id == T_double) || (fieldBinding.type.id == T_long)) + stackDepth += 2; + else + stackDepth += 1; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_getstatic; + writeUnsignedShort(constantPool.literalIndex(fieldBinding)); +} +public void getTYPE(int baseTypeID) { + countLabels = 0; + if (++stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_getstatic; + switch (baseTypeID) { + case T_byte : + // getstatic: java.lang.Byte.TYPE + if (DEBUG) System.out.println(position + "\t\tgetstatic: java.lang.Byte.TYPE"); //$NON-NLS-1$ + writeUnsignedShort(constantPool.literalIndexForJavaLangByteTYPE()); + break; + case T_short : + // getstatic: java.lang.Short.TYPE + if (DEBUG) System.out.println(position + "\t\tgetstatic: java.lang.Short.TYPE"); //$NON-NLS-1$ + writeUnsignedShort(constantPool.literalIndexForJavaLangShortTYPE()); + break; + case T_char : + // getstatic: java.lang.Character.TYPE + if (DEBUG) System.out.println(position + "\t\tgetstatic: java.lang.Character.TYPE"); //$NON-NLS-1$ + writeUnsignedShort(constantPool.literalIndexForJavaLangCharacterTYPE()); + break; + case T_int : + // getstatic: java.lang.Integer.TYPE + if (DEBUG) System.out.println(position + "\t\tgetstatic: java.lang.Integer.TYPE"); //$NON-NLS-1$ + writeUnsignedShort(constantPool.literalIndexForJavaLangIntegerTYPE()); + break; + case T_long : + // getstatic: java.lang.Long.TYPE + if (DEBUG) System.out.println(position + "\t\tgetstatic: java.lang.Long.TYPE"); //$NON-NLS-1$ + writeUnsignedShort(constantPool.literalIndexForJavaLangLongTYPE()); + break; + case T_float : + // getstatic: java.lang.Float.TYPE + if (DEBUG) System.out.println(position + "\t\tgetstatic: java.lang.Float.TYPE"); //$NON-NLS-1$ + writeUnsignedShort(constantPool.literalIndexForJavaLangFloatTYPE()); + break; + case T_double : + // getstatic: java.lang.Double.TYPE + if (DEBUG) System.out.println(position + "\t\tgetstatic: java.lang.Double.TYPE"); //$NON-NLS-1$ + writeUnsignedShort(constantPool.literalIndexForJavaLangDoubleTYPE()); + break; + case T_boolean : + // getstatic: java.lang.Boolean.TYPE + if (DEBUG) System.out.println(position + "\t\tgetstatic: java.lang.Boolean.TYPE"); //$NON-NLS-1$ + writeUnsignedShort(constantPool.literalIndexForJavaLangBooleanTYPE()); + break; + case T_void : + // getstatic: java.lang.Void.TYPE + if (DEBUG) System.out.println(position + "\t\tgetstatic: java.lang.Void.TYPE"); //$NON-NLS-1$ + writeUnsignedShort(constantPool.literalIndexForJavaLangVoidTYPE()); + break; + } +} +/** + * We didn't call it goto, because there is a conflit with the goto keyword + */ +final public void goto_(Label label) { + if (this.wideMode) { + this.goto_w(label); + return; + } + if (DEBUG) System.out.println(position + "\t\tgoto:"+label); //$NON-NLS-1$ + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + label.inlineForwardReferencesFromLabelsTargeting(position); + /* + Possible optimization for code such as: + public Object foo() { + boolean b = true; + if (b) { + if (b) + return null; + } else { + if (b) { + return null; + } + } + return null; + } + The goto around the else block for the first if will + be unreachable, because the thenClause of the second if + returns. + See inlineForwardReferencesFromLabelsTargeting defined + on the Label class for the remaining part of this + optimization. + if (!lbl.isBranchTarget(position)) { + switch(bCodeStream[classFileOffset-1]) { + case OPC_return : + case OPC_areturn: + return; + } + }*/ + position++; + bCodeStream[classFileOffset++] = OPC_goto; + label.branch(); +} + +final public void goto_w(Label lbl) { + if (DEBUG) System.out.println(position + "\t\tgotow:"+lbl); //$NON-NLS-1$ + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_goto_w; + lbl.branchWide(); +} +final public void i2b() { + if (DEBUG) System.out.println(position + "\t\ti2b"); //$NON-NLS-1$ + countLabels = 0; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_i2b; +} +final public void i2c() { + if (DEBUG) System.out.println(position + "\t\ti2c"); //$NON-NLS-1$ + countLabels = 0; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_i2c; +} +final public void i2d() { + if (DEBUG) System.out.println(position + "\t\ti2d"); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_i2d; +} +final public void i2f() { + if (DEBUG) System.out.println(position + "\t\ti2f"); //$NON-NLS-1$ + countLabels = 0; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_i2f; +} +final public void i2l() { + if (DEBUG) System.out.println(position + "\t\ti2l"); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_i2l; +} +final public void i2s() { + if (DEBUG) System.out.println(position + "\t\ti2s"); //$NON-NLS-1$ + countLabels = 0; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_i2s; +} +final public void iadd() { + if (DEBUG) System.out.println(position + "\t\tiadd"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_iadd; +} +final public void iaload() { + if (DEBUG) System.out.println(position + "\t\tiaload"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_iaload; +} +final public void iand() { + if (DEBUG) System.out.println(position + "\t\tiand"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_iand; +} +final public void iastore() { + if (DEBUG) System.out.println(position + "\t\tiastore"); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 3; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_iastore; +} +final public void iconst_0() { + if (DEBUG) System.out.println(position + "\t\ticonst_0"); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_iconst_0; +} +final public void iconst_1() { + if (DEBUG) System.out.println(position + "\t\ticonst_1"); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_iconst_1; +} +final public void iconst_2() { + if (DEBUG) System.out.println(position + "\t\ticonst_2"); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_iconst_2; +} +final public void iconst_3() { + if (DEBUG) System.out.println(position + "\t\ticonst_3"); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_iconst_3; +} +final public void iconst_4() { + if (DEBUG) System.out.println(position + "\t\ticonst_4"); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_iconst_4; +} +final public void iconst_5() { + if (DEBUG) System.out.println(position + "\t\ticonst_5"); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_iconst_5; +} +final public void iconst_m1() { + if (DEBUG) System.out.println(position + "\t\ticonst_m1"); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_iconst_m1; +} +final public void idiv() { + if (DEBUG) System.out.println(position + "\t\tidiv"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_idiv; +} +final public void if_acmpeq(Label lbl) { + if (DEBUG) System.out.println(position + "\t\tif_acmpeq:"+lbl); //$NON-NLS-1$ + countLabels = 0; + stackDepth-=2; + if (this.wideMode) { + generateWideRevertedConditionalBranch(OPC_if_acmpne, lbl); + } else { + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_if_acmpeq; + lbl.branch(); + } +} +final public void if_acmpne(Label lbl) { + if (DEBUG) System.out.println(position + "\t\tif_acmpne:"+lbl); //$NON-NLS-1$ + countLabels = 0; + stackDepth-=2; + if (this.wideMode) { + generateWideRevertedConditionalBranch(OPC_if_acmpeq, lbl); + } else { + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_if_acmpne; + lbl.branch(); + } +} +final public void if_icmpeq(Label lbl) { + if (DEBUG) System.out.println(position + "\t\tif_cmpeq:"+lbl); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 2; + if (this.wideMode) { + generateWideRevertedConditionalBranch(OPC_if_icmpne, lbl); + } else { + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_if_icmpeq; + lbl.branch(); + } +} +final public void if_icmpge(Label lbl) { + if (DEBUG) System.out.println(position + "\t\tif_iacmpge:"+lbl); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 2; + if (this.wideMode) { + generateWideRevertedConditionalBranch(OPC_if_icmplt, lbl); + } else { + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_if_icmpge; + lbl.branch(); + } +} +final public void if_icmpgt(Label lbl) { + if (DEBUG) System.out.println(position + "\t\tif_iacmpgt:"+lbl); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 2; + if (this.wideMode) { + generateWideRevertedConditionalBranch(OPC_if_icmple, lbl); + } else { + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_if_icmpgt; + lbl.branch(); + } +} +final public void if_icmple(Label lbl) { + if (DEBUG) System.out.println(position + "\t\tif_iacmple:"+lbl); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 2; + if (this.wideMode) { + generateWideRevertedConditionalBranch(OPC_if_icmpgt, lbl); + } else { + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_if_icmple; + lbl.branch(); + } +} +final public void if_icmplt(Label lbl) { + if (DEBUG) System.out.println(position + "\t\tif_iacmplt:"+lbl); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 2; + if (this.wideMode) { + generateWideRevertedConditionalBranch(OPC_if_icmpge, lbl); + } else { + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_if_icmplt; + lbl.branch(); + } +} +final public void if_icmpne(Label lbl) { + if (DEBUG) System.out.println(position + "\t\tif_iacmpne:"+lbl); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 2; + if (this.wideMode) { + generateWideRevertedConditionalBranch(OPC_if_icmpeq, lbl); + } else { + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_if_icmpne; + lbl.branch(); + } +} +final public void ifeq(Label lbl) { + if (DEBUG) System.out.println(position + "\t\tifeq:"+lbl); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (this.wideMode) { + generateWideRevertedConditionalBranch(OPC_ifne, lbl); + } else { + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_ifeq; + lbl.branch(); + } +} +final public void ifge(Label lbl) { + if (DEBUG) System.out.println(position + "\t\tifge:"+lbl); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (this.wideMode) { + generateWideRevertedConditionalBranch(OPC_iflt, lbl); + } else { + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_ifge; + lbl.branch(); + } +} +final public void ifgt(Label lbl) { + if (DEBUG) System.out.println(position + "\t\tifgt:"+lbl); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (this.wideMode) { + generateWideRevertedConditionalBranch(OPC_ifle, lbl); + } else { + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_ifgt; + lbl.branch(); + } +} +final public void ifle(Label lbl) { + if (DEBUG) System.out.println(position + "\t\tifle:"+lbl); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (this.wideMode) { + generateWideRevertedConditionalBranch(OPC_ifgt, lbl); + } else { + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_ifle; + lbl.branch(); + } +} +final public void iflt(Label lbl) { + if (DEBUG) System.out.println(position + "\t\tiflt:"+lbl); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (this.wideMode) { + generateWideRevertedConditionalBranch(OPC_ifge, lbl); + } else { + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_iflt; + lbl.branch(); + } +} +final public void ifne(Label lbl) { + if (DEBUG) System.out.println(position + "\t\tifne:"+lbl); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (this.wideMode) { + generateWideRevertedConditionalBranch(OPC_ifeq, lbl); + } else { + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_ifne; + lbl.branch(); + } +} +final public void ifnonnull(Label lbl) { + if (DEBUG) System.out.println(position + "\t\tifnonnull:"+lbl); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (this.wideMode) { + generateWideRevertedConditionalBranch(OPC_ifnull, lbl); + } else { + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_ifnonnull; + lbl.branch(); + } +} +final public void ifnull(Label lbl) { + if (DEBUG) System.out.println(position + "\t\tifnull:"+lbl); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (this.wideMode) { + generateWideRevertedConditionalBranch(OPC_ifnonnull, lbl); + } else { + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_ifnull; + lbl.branch(); + } +} +final public void iinc(int index, int value) { + if (DEBUG) System.out.println(position + "\t\tiinc:"+index+","+value); //$NON-NLS-1$ //$NON-NLS-2$ + countLabels = 0; + if ((index > 255) || (value < -128 || value > 127)) { // have to widen + if (classFileOffset + 3 >= bCodeStream.length) { + resizeByteArray(); + } + position += 2; + bCodeStream[classFileOffset++] = OPC_wide; + bCodeStream[classFileOffset++] = OPC_iinc; + writeUnsignedShort(index); + writeSignedShort(value); + } else { + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position += 3; + bCodeStream[classFileOffset++] = OPC_iinc; + bCodeStream[classFileOffset++] = (byte) index; + bCodeStream[classFileOffset++] = (byte) value; + } +} +final public void iload(int iArg) { + if (DEBUG) System.out.println(position + "\t\tiload:"+iArg); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (maxLocals <= iArg) { + maxLocals = iArg + 1; + } + if (stackDepth > stackMax) + stackMax = stackDepth; + if (iArg > 255) { // Widen + if (classFileOffset + 3 >= bCodeStream.length) { + resizeByteArray(); + } + position += 2; + bCodeStream[classFileOffset++] = OPC_wide; + bCodeStream[classFileOffset++] = OPC_iload; + writeUnsignedShort(iArg); + } else { + if (classFileOffset + 1 >= bCodeStream.length) { + resizeByteArray(); + } + position += 2; + bCodeStream[classFileOffset++] = OPC_iload; + bCodeStream[classFileOffset++] = (byte) iArg; + } +} +final public void iload_0() { + if (DEBUG) System.out.println(position + "\t\tiload_0"); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (maxLocals <= 0) { + maxLocals = 1; + } + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_iload_0; +} +final public void iload_1() { + if (DEBUG) System.out.println(position + "\t\tiload_1"); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (maxLocals <= 1) { + maxLocals = 2; + } + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_iload_1; +} +final public void iload_2() { + if (DEBUG) System.out.println(position + "\t\tiload_2"); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (maxLocals <= 2) { + maxLocals = 3; + } + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_iload_2; +} +final public void iload_3() { + if (DEBUG) System.out.println(position + "\t\tiload_3"); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (maxLocals <= 3) { + maxLocals = 4; + } + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_iload_3; +} +final public void imul() { + if (DEBUG) System.out.println(position + "\t\timul"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_imul; +} +public void incrementTemp(LocalVariableBinding localBinding, int value) { + if (value == (short) value) { + this.iinc(localBinding.resolvedPosition, value); + return; + } + load(localBinding); + this.ldc(value); + this.iadd(); + store(localBinding, false); +} +public void incrStackSize(int offset) { + if ((stackDepth += offset) > stackMax) + stackMax = stackDepth; +} +public int indexOfSameLineEntrySincePC(int pc, int line) { + for (int index = pc, max = pcToSourceMapSize; index < max; index+=2) { + if (pcToSourceMap[index+1] == line) + return index; + } + return -1; +} +final public void ineg() { + if (DEBUG) System.out.println(position + "\t\tineg"); //$NON-NLS-1$ + countLabels = 0; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_ineg; +} +public void init(ClassFile targetClassFile) { + this.classFile = targetClassFile; + this.constantPool = targetClassFile.constantPool; + this.bCodeStream = targetClassFile.contents; + this.classFileOffset = targetClassFile.contentsOffset; + this.startingClassFileOffset = this.classFileOffset; + pcToSourceMapSize = 0; + lastEntryPC = 0; + int length = visibleLocals.length; + if (noVisibleLocals.length < length) { + noVisibleLocals = new LocalVariableBinding[length]; + } + System.arraycopy(noVisibleLocals, 0, visibleLocals, 0, length); + visibleLocalsCount = 0; + + length = locals.length; + if (noLocals.length < length) { + noLocals = new LocalVariableBinding[length]; + } + System.arraycopy(noLocals, 0, locals, 0, length); + allLocalsCounter = 0; + + length = exceptionHandlers.length; + if (noExceptionHandlers.length < length) { + noExceptionHandlers = new ExceptionLabel[length]; + } + System.arraycopy(noExceptionHandlers, 0, exceptionHandlers, 0, length); + exceptionHandlersNumber = 0; + + length = labels.length; + if (noLabels.length < length) { + noLabels = new Label[length]; + } + System.arraycopy(noLabels, 0, labels, 0, length); + countLabels = 0; + + stackMax = 0; + stackDepth = 0; + maxLocals = 0; + position = 0; +} +/** + * @param methodBinding the given method binding to initialize the max locals + */ +public void initializeMaxLocals(MethodBinding methodBinding) { + + maxLocals = (methodBinding == null || methodBinding.isStatic()) ? 0 : 1; + // take into account the synthetic parameters + if (methodBinding != null) { + if (methodBinding.isConstructor() && methodBinding.declaringClass.isNestedType()) { + ReferenceBinding enclosingInstanceTypes[]; + if ((enclosingInstanceTypes = methodBinding.declaringClass.syntheticEnclosingInstanceTypes()) != null) { + for (int i = 0, max = enclosingInstanceTypes.length; i < max; i++) { + maxLocals++; // an enclosingInstanceType can only be a reference binding. It cannot be + // LongBinding or DoubleBinding + } + } + SyntheticArgumentBinding syntheticArguments[]; + if ((syntheticArguments = methodBinding.declaringClass.syntheticOuterLocalVariables()) != null) { + for (int i = 0, max = syntheticArguments.length; i < max; i++) { + TypeBinding argType; + if (((argType = syntheticArguments[i].type) == LongBinding) || (argType == DoubleBinding)) { + maxLocals += 2; + } else { + maxLocals++; + } + } + } + } + TypeBinding[] arguments; + if ((arguments = methodBinding.parameters) != null) { + for (int i = 0, max = arguments.length; i < max; i++) { + TypeBinding argType; + if (((argType = arguments[i]) == LongBinding) || (argType == DoubleBinding)) { + maxLocals += 2; + } else { + maxLocals++; + } + } + } + } +} +/** + * This methods searches for an existing entry inside the pcToSourceMap table with a pc equals to @pc. + * If there is an existing entry it returns -1 (no insertion required). + * Otherwise it returns the index where the entry for the pc has to be inserted. + * This is based on the fact that the pcToSourceMap table is sorted according to the pc. + * + * @param pcToSourceMap the given pcToSourceMap array + * @param length the given length + * @param pc the given pc + * @return int + */ +public static int insertionIndex(int[] pcToSourceMap, int length, int pc) { + int g = 0; + int d = length - 2; + int m = 0; + while (g <= d) { + m = (g + d) / 2; + // we search only on even indexes + if ((m % 2) != 0) + m--; + int currentPC = pcToSourceMap[m]; + if (pc < currentPC) { + d = m - 2; + } else + if (pc > currentPC) { + g = m + 2; + } else { + return -1; + } + } + if (pc < pcToSourceMap[m]) + return m; + return m + 2; +} +/** + * We didn't call it instanceof because there is a conflit with the + * instanceof keyword + */ +final public void instance_of(TypeBinding typeBinding) { + if (DEBUG) System.out.println(position + "\t\tinstance_of:"+typeBinding); //$NON-NLS-1$ + countLabels = 0; + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_instanceof; + writeUnsignedShort(constantPool.literalIndex(typeBinding)); +} +public void invokeClassForName() { + // invokestatic: java.lang.Class.forName(Ljava.lang.String;)Ljava.lang.Class; + if (DEBUG) System.out.println(position + "\t\tinvokestatic: java.lang.Class.forName(Ljava.lang.String;)Ljava.lang.Class;"); //$NON-NLS-1$ + countLabels = 0; + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_invokestatic; + writeUnsignedShort(constantPool.literalIndexForJavaLangClassForName()); +} + +public void invokeJavaLangClassDesiredAssertionStatus() { + // invokevirtual: java.lang.Class.desiredAssertionStatus()Z; + if (DEBUG) System.out.println(position + "\t\tinvokevirtual: java.lang.Class.desiredAssertionStatus()Z;"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_invokevirtual; + writeUnsignedShort(constantPool.literalIndexForJavaLangClassDesiredAssertionStatus()); +} + +public void invokeJavaLangClassGetComponentType() { + // invokevirtual: java.lang.Class.getComponentType()java.lang.Class; + if (DEBUG) System.out.println(position + "\t\tinvokevirtual: java.lang.Class.getComponentType()java.lang.Class;"); //$NON-NLS-1$ + countLabels = 0; + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_invokevirtual; + writeUnsignedShort(constantPool.literalIndexForJavaLangClassGetComponentType()); +} + +final public void invokeinterface(MethodBinding methodBinding) { + // initialized to 1 to take into account this immediately + if (DEBUG) System.out.println(position + "\t\tinvokeinterface: " + methodBinding); //$NON-NLS-1$ + countLabels = 0; + int argCount = 1; + int id; + if (classFileOffset + 4 >= bCodeStream.length) { + resizeByteArray(); + } + position += 3; + bCodeStream[classFileOffset++] = OPC_invokeinterface; + writeUnsignedShort(constantPool.literalIndex(methodBinding)); + for (int i = methodBinding.parameters.length - 1; i >= 0; i--) + if (((id = methodBinding.parameters[i].id) == T_double) || (id == T_long)) + argCount += 2; + else + argCount += 1; + bCodeStream[classFileOffset++] = (byte) argCount; + // Generate a 0 into the byte array. Like the array is already fill with 0, we just need to increment + // the number of bytes. + bCodeStream[classFileOffset++] = 0; + if (((id = methodBinding.returnType.id) == T_double) || (id == T_long)) { + stackDepth += (2 - argCount); + } else { + if (id == T_void) { + stackDepth -= argCount; + } else { + stackDepth += (1 - argCount); + } + } + if (stackDepth > stackMax) { + stackMax = stackDepth; + } +} +public void invokeJavaLangErrorConstructor() { + // invokespecial: java.lang.Error(Ljava.lang.String;)V + if (DEBUG) System.out.println(position + "\t\tinvokespecial: java.lang.Error(Ljava.lang.String;)V"); //$NON-NLS-1$ + countLabels = 0; + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_invokespecial; + stackDepth -= 2; + writeUnsignedShort(constantPool.literalIndexForJavaLangErrorConstructor()); +} +public void invokeNoClassDefFoundErrorStringConstructor() { + // invokespecial: java.lang.NoClassDefFoundError.(Ljava.lang.String;)V + if (DEBUG) System.out.println(position + "\t\tinvokespecial: java.lang.NoClassDefFoundError.(Ljava.lang.String;)V"); //$NON-NLS-1$ + countLabels = 0; + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_invokespecial; + stackDepth -= 2; + writeUnsignedShort(constantPool.literalIndexForJavaLangNoClassDefFoundErrorStringConstructor()); +} +public void invokeObjectGetClass() { + // invokevirtual: java.lang.Object.getClass()Ljava.lang.Class; + if (DEBUG) System.out.println(position + "\t\tinvokevirtual: java.lang.Object.getClass()Ljava.lang.Class;"); //$NON-NLS-1$ + countLabels = 0; + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_invokevirtual; + writeUnsignedShort(constantPool.literalIndexForJavaLangObjectGetClass()); +} + +final public void invokespecial(MethodBinding methodBinding) { + if (DEBUG) System.out.println(position + "\t\tinvokespecial:"+methodBinding); //$NON-NLS-1$ + // initialized to 1 to take into account this immediately + countLabels = 0; + int argCount = 1; + int id; + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_invokespecial; + writeUnsignedShort(constantPool.literalIndex(methodBinding)); + if (methodBinding.isConstructor() && methodBinding.declaringClass.isNestedType()) { + // enclosing instances + TypeBinding[] syntheticArgumentTypes = methodBinding.declaringClass.syntheticEnclosingInstanceTypes(); + if (syntheticArgumentTypes != null) { + for (int i = 0, max = syntheticArgumentTypes.length; i < max; i++) { + if (((id = syntheticArgumentTypes[i].id) == T_double) || (id == T_long)) { + argCount += 2; + } else { + argCount++; + } + } + } + // outer local variables + SyntheticArgumentBinding[] syntheticArguments = methodBinding.declaringClass.syntheticOuterLocalVariables(); + if (syntheticArguments != null) { + for (int i = 0, max = syntheticArguments.length; i < max; i++) { + if (((id = syntheticArguments[i].type.id) == T_double) || (id == T_long)) { + argCount += 2; + } else { + argCount++; + } + } + } + } + for (int i = methodBinding.parameters.length - 1; i >= 0; i--) + if (((id = methodBinding.parameters[i].id) == T_double) || (id == T_long)) + argCount += 2; + else + argCount++; + if (((id = methodBinding.returnType.id) == T_double) || (id == T_long)) + stackDepth += (2 - argCount); + else + if (id == T_void) + stackDepth -= argCount; + else + stackDepth += (1 - argCount); + if (stackDepth > stackMax) + stackMax = stackDepth; +} +final public void invokestatic(MethodBinding methodBinding) { + if (DEBUG) System.out.println(position + "\t\tinvokestatic:"+methodBinding); //$NON-NLS-1$ + // initialized to 0 to take into account that there is no this for + // a static method + countLabels = 0; + int argCount = 0; + int id; + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_invokestatic; + writeUnsignedShort(constantPool.literalIndex(methodBinding)); + for (int i = methodBinding.parameters.length - 1; i >= 0; i--) + if (((id = methodBinding.parameters[i].id) == T_double) || (id == T_long)) + argCount += 2; + else + argCount += 1; + if (((id = methodBinding.returnType.id) == T_double) || (id == T_long)) + stackDepth += (2 - argCount); + else + if (id == T_void) + stackDepth -= argCount; + else + stackDepth += (1 - argCount); + if (stackDepth > stackMax) + stackMax = stackDepth; +} +/** + * The equivalent code performs a string conversion of the TOS + * @param typeID int + */ +public void invokeStringBufferAppendForType(int typeID) { + if (DEBUG) System.out.println(position + "\t\tinvokevirtual: java.lang.StringBuffer.append(...)"); //$NON-NLS-1$ + countLabels = 0; + int usedTypeID; + if (typeID == T_null) + usedTypeID = T_String; + else + usedTypeID = typeID; + // invokevirtual + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_invokevirtual; + writeUnsignedShort(constantPool.literalIndexForJavaLangStringBufferAppend(typeID)); + if ((usedTypeID == T_long) || (usedTypeID == T_double)) + stackDepth -= 2; + else + stackDepth--; +} + +public void invokeJavaLangAssertionErrorConstructor(int typeBindingID) { + // invokespecial: java.lang.AssertionError.(typeBindingID)V + if (DEBUG) System.out.println(position + "\t\tinvokespecial: java.lang.AssertionError.(typeBindingID)V"); //$NON-NLS-1$ + countLabels = 0; + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_invokespecial; + writeUnsignedShort(constantPool.literalIndexForJavaLangAssertionErrorConstructor(typeBindingID)); + stackDepth -= 2; +} + +public void invokeJavaLangAssertionErrorDefaultConstructor() { + // invokespecial: java.lang.AssertionError.()V + if (DEBUG) System.out.println(position + "\t\tinvokespecial: java.lang.AssertionError.()V"); //$NON-NLS-1$ + countLabels = 0; + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_invokespecial; + writeUnsignedShort(constantPool.literalIndexForJavaLangAssertionErrorDefaultConstructor()); + stackDepth --; +} + +public void invokeStringBufferDefaultConstructor() { + // invokespecial: java.lang.StringBuffer.()V + if (DEBUG) System.out.println(position + "\t\tinvokespecial: java.lang.StringBuffer.()V"); //$NON-NLS-1$ + countLabels = 0; + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_invokespecial; + writeUnsignedShort(constantPool.literalIndexForJavaLangStringBufferDefaultConstructor()); + stackDepth--; +} +public void invokeStringBufferStringConstructor() { + // invokespecial: java.lang.StringBuffer.(Ljava.lang.String;)V + if (DEBUG) System.out.println(position + "\t\tjava.lang.StringBuffer.(Ljava.lang.String;)V"); //$NON-NLS-1$ + countLabels = 0; + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_invokespecial; + writeUnsignedShort(constantPool.literalIndexForJavaLangStringBufferConstructor()); + stackDepth -= 2; +} + +public void invokeStringBufferToString() { + // invokevirtual: StringBuffer.toString()Ljava.lang.String; + if (DEBUG) System.out.println(position + "\t\tinvokevirtual: StringBuffer.toString()Ljava.lang.String;"); //$NON-NLS-1$ + countLabels = 0; + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_invokevirtual; + writeUnsignedShort(constantPool.literalIndexForJavaLangStringBufferToString()); +} +public void invokeStringIntern() { + // invokevirtual: java.lang.String.intern() + if (DEBUG) System.out.println(position + "\t\tinvokevirtual: java.lang.String.intern()"); //$NON-NLS-1$ + countLabels = 0; + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_invokevirtual; + writeUnsignedShort(constantPool.literalIndexForJavaLangStringIntern()); +} +public void invokeStringValueOf(int typeID) { + // invokestatic: java.lang.String.valueOf(argumentType) + if (DEBUG) System.out.println(position + "\t\tinvokestatic: java.lang.String.valueOf(...)"); //$NON-NLS-1$ + countLabels = 0; + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_invokestatic; + writeUnsignedShort(constantPool.literalIndexForJavaLangStringValueOf(typeID)); +} +public void invokeThrowableGetMessage() { + // invokevirtual: java.lang.Throwable.getMessage()Ljava.lang.String; + if (DEBUG) System.out.println(position + "\t\tinvokevirtual: java.lang.Throwable.getMessage()Ljava.lang.String;"); //$NON-NLS-1$ + countLabels = 0; + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_invokevirtual; + writeUnsignedShort(constantPool.literalIndexForJavaLangThrowableGetMessage()); +} +final public void invokevirtual(MethodBinding methodBinding) { + if (DEBUG) System.out.println(position + "\t\tinvokevirtual:"+methodBinding); //$NON-NLS-1$ + // initialized to 1 to take into account this immediately + countLabels = 0; + int argCount = 1; + int id; + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_invokevirtual; + writeUnsignedShort(constantPool.literalIndex(methodBinding)); + for (int i = methodBinding.parameters.length - 1; i >= 0; i--) + if (((id = methodBinding.parameters[i].id) == T_double) || (id == T_long)) + argCount += 2; + else + argCount++; + if (((id = methodBinding.returnType.id) == T_double) || (id == T_long)) + stackDepth += (2 - argCount); + else + if (id == T_void) + stackDepth -= argCount; + else + stackDepth += (1 - argCount); + if (stackDepth > stackMax) + stackMax = stackDepth; +} +final public void ior() { + if (DEBUG) System.out.println(position + "\t\tior"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_ior; +} +final public void irem() { + if (DEBUG) System.out.println(position + "\t\tirem"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_irem; +} +final public void ireturn() { + if (DEBUG) System.out.println(position + "\t\tireturn"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + // the stackDepth should be equal to 0 + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_ireturn; +} +public boolean isDefinitelyAssigned(Scope scope, int initStateIndex, LocalVariableBinding local) { + // Dependant of UnconditionalFlowInfo.isDefinitelyAssigned(..) + if (initStateIndex == -1) + return false; + if (local.isArgument) { + return true; + } + int localPosition = local.id + maxFieldCount; + MethodScope methodScope = scope.methodScope(); + // id is zero-based + if (localPosition < UnconditionalFlowInfo.BitCacheSize) { + return (methodScope.definiteInits[initStateIndex] & (1L << localPosition)) != 0; // use bits + } + // use extra vector + long[] extraInits = methodScope.extraDefiniteInits[initStateIndex]; + if (extraInits == null) + return false; // if vector not yet allocated, then not initialized + int vectorIndex; + if ((vectorIndex = (localPosition / UnconditionalFlowInfo.BitCacheSize) - 1) >= extraInits.length) + return false; // if not enough room in vector, then not initialized + return ((extraInits[vectorIndex]) & (1L << (localPosition % UnconditionalFlowInfo.BitCacheSize))) != 0; +} +final public void ishl() { + if (DEBUG) System.out.println(position + "\t\tishl"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_ishl; +} +final public void ishr() { + if (DEBUG) System.out.println(position + "\t\tishr"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_ishr; +} +final public void istore(int iArg) { + if (DEBUG) System.out.println(position + "\t\tistore:"+iArg); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (maxLocals <= iArg) { + maxLocals = iArg + 1; + } + if (iArg > 255) { // Widen + if (classFileOffset + 3 >= bCodeStream.length) { + resizeByteArray(); + } + position += 2; + bCodeStream[classFileOffset++] = OPC_wide; + bCodeStream[classFileOffset++] = OPC_istore; + writeUnsignedShort(iArg); + } else { + if (classFileOffset + 1 >= bCodeStream.length) { + resizeByteArray(); + } + position += 2; + bCodeStream[classFileOffset++] = OPC_istore; + bCodeStream[classFileOffset++] = (byte) iArg; + } +} +final public void istore_0() { + if (DEBUG) System.out.println(position + "\t\tistore_0"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (maxLocals == 0) { + maxLocals = 1; + } + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_istore_0; +} +final public void istore_1() { + if (DEBUG) System.out.println(position + "\t\tistore_1"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (maxLocals <= 1) { + maxLocals = 2; + } + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_istore_1; +} +final public void istore_2() { + if (DEBUG) System.out.println(position + "\t\tistore_2"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (maxLocals <= 2) { + maxLocals = 3; + } + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_istore_2; +} +final public void istore_3() { + if (DEBUG) System.out.println(position + "\t\tistore_3"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (maxLocals <= 3) { + maxLocals = 4; + } + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_istore_3; +} +final public void isub() { + if (DEBUG) System.out.println(position + "\t\tisub"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_isub; +} +final public void iushr() { + if (DEBUG) System.out.println(position + "\t\tiushr"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_iushr; +} +final public void ixor() { + if (DEBUG) System.out.println(position + "\t\tixor"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_ixor; +} +final public void jsr(Label lbl) { + if (this.wideMode) { + this.jsr_w(lbl); + return; + } + if (DEBUG) System.out.println(position + "\t\tjsr"+lbl); //$NON-NLS-1$ + countLabels = 0; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_jsr; + lbl.branch(); +} +final public void jsr_w(Label lbl) { + if (DEBUG) System.out.println(position + "\t\tjsr_w"+lbl); //$NON-NLS-1$ + countLabels = 0; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_jsr_w; + lbl.branchWide(); +} +final public void l2d() { + if (DEBUG) System.out.println(position + "\t\tl2d"); //$NON-NLS-1$ + countLabels = 0; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_l2d; +} +final public void l2f() { + if (DEBUG) System.out.println(position + "\t\tl2f"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_l2f; +} +final public void l2i() { + if (DEBUG) System.out.println(position + "\t\tl2i"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_l2i; +} +final public void ladd() { + if (DEBUG) System.out.println(position + "\t\tladd"); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 2; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_ladd; +} +final public void laload() { + if (DEBUG) System.out.println(position + "\t\tlaload"); //$NON-NLS-1$ + countLabels = 0; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_laload; +} +final public void land() { + if (DEBUG) System.out.println(position + "\t\tland"); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 2; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_land; +} +final public void lastore() { + if (DEBUG) System.out.println(position + "\t\tlastore"); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 4; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_lastore; +} +final public void lcmp() { + if (DEBUG) System.out.println(position + "\t\tlcmp"); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 3; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_lcmp; +} +final public void lconst_0() { + if (DEBUG) System.out.println(position + "\t\tlconst_0"); //$NON-NLS-1$ + countLabels = 0; + stackDepth += 2; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_lconst_0; +} +final public void lconst_1() { + if (DEBUG) System.out.println(position + "\t\tlconst_1"); //$NON-NLS-1$ + countLabels = 0; + stackDepth += 2; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_lconst_1; +} +final public void ldc(float constant) { + if (DEBUG) System.out.println(position + "\t\tldc:"+constant); //$NON-NLS-1$ + countLabels = 0; + int index = constantPool.literalIndex(constant); + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (index > 255) { + // Generate a ldc_w + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_ldc_w; + writeUnsignedShort(index); + } else { + // Generate a ldc + if (classFileOffset + 1 >= bCodeStream.length) { + resizeByteArray(); + } + position += 2; + bCodeStream[classFileOffset++] = OPC_ldc; + bCodeStream[classFileOffset++] = (byte) index; + } +} +final public void ldc(int constant) { + if (DEBUG) System.out.println(position + "\t\tldc:"+constant); //$NON-NLS-1$ + countLabels = 0; + int index = constantPool.literalIndex(constant); + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (index > 255) { + // Generate a ldc_w + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_ldc_w; + writeUnsignedShort(index); + } else { + // Generate a ldc + if (classFileOffset + 1 >= bCodeStream.length) { + resizeByteArray(); + } + position += 2; + bCodeStream[classFileOffset++] = OPC_ldc; + bCodeStream[classFileOffset++] = (byte) index; + } +} +final public void ldc(String constant) { + if (DEBUG) System.out.println(position + "\t\tldc:"+constant); //$NON-NLS-1$ + countLabels = 0; + int currentConstantPoolIndex = constantPool.currentIndex; + int currentConstantPoolOffset = constantPool.currentOffset; + int currentCodeStreamPosition = position; + int index = constantPool.literalIndexForLdc(constant.toCharArray()); + if (index > 0) { + // the string already exists inside the constant pool + // we reuse the same index + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (index > 255) { + // Generate a ldc_w + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_ldc_w; + writeUnsignedShort(index); + } else { + // Generate a ldc + if (classFileOffset + 1 >= bCodeStream.length) { + resizeByteArray(); + } + position += 2; + bCodeStream[classFileOffset++] = OPC_ldc; + bCodeStream[classFileOffset++] = (byte) index; + } + } else { + // the string is too big to be utf8-encoded in one pass. + // we have to split it into different pieces. + // first we clean all side-effects due to the code above + // this case is very rare, so we can afford to lose time to handle it + char[] constantChars = constant.toCharArray(); + position = currentCodeStreamPosition; + constantPool.currentIndex = currentConstantPoolIndex; + constantPool.currentOffset = currentConstantPoolOffset; + constantPool.stringCache.remove(constantChars); + constantPool.UTF8Cache.remove(constantChars); + int i = 0; + int length = 0; + int constantLength = constant.length(); + byte[] utf8encoding = new byte[Math.min(constantLength + 100, 65535)]; + int utf8encodingLength = 0; + while ((length < 65532) && (i < constantLength)) { + char current = constantChars[i]; + // we resize the byte array immediately if necessary + if (length + 3 > (utf8encodingLength = utf8encoding.length)) { + System.arraycopy(utf8encoding, 0, utf8encoding = new byte[Math.min(utf8encodingLength + 100, 65535)], 0, length); + } + if ((current >= 0x0001) && (current <= 0x007F)) { + // we only need one byte: ASCII table + utf8encoding[length++] = (byte) current; + } else { + if (current > 0x07FF) { + // we need 3 bytes + utf8encoding[length++] = (byte) (0xE0 | ((current >> 12) & 0x0F)); // 0xE0 = 1110 0000 + utf8encoding[length++] = (byte) (0x80 | ((current >> 6) & 0x3F)); // 0x80 = 1000 0000 + utf8encoding[length++] = (byte) (0x80 | (current & 0x3F)); // 0x80 = 1000 0000 + } else { + // we can be 0 or between 0x0080 and 0x07FF + // In that case we only need 2 bytes + utf8encoding[length++] = (byte) (0xC0 | ((current >> 6) & 0x1F)); // 0xC0 = 1100 0000 + utf8encoding[length++] = (byte) (0x80 | (current & 0x3F)); // 0x80 = 1000 0000 + } + } + i++; + } + // check if all the string is encoded (PR 1PR2DWJ) + // the string is too big to be encoded in one pass + newStringBuffer(); + dup(); + // write the first part + char[] subChars = new char[i]; + System.arraycopy(constantChars, 0, subChars, 0, i); + System.arraycopy(utf8encoding, 0, utf8encoding = new byte[length], 0, length); + index = constantPool.literalIndex(subChars, utf8encoding); + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (index > 255) { + // Generate a ldc_w + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_ldc_w; + writeUnsignedShort(index); + } else { + // Generate a ldc + if (classFileOffset + 1 >= bCodeStream.length) { + resizeByteArray(); + } + position += 2; + bCodeStream[classFileOffset++] = OPC_ldc; + bCodeStream[classFileOffset++] = (byte) index; + } + // write the remaining part + invokeStringBufferStringConstructor(); + while (i < constantLength) { + length = 0; + utf8encoding = new byte[Math.min(constantLength - i + 100, 65535)]; + int startIndex = i; + while ((length < 65532) && (i < constantLength)) { + char current = constantChars[i]; + // we resize the byte array immediately if necessary + if (constantLength + 2 > (utf8encodingLength = utf8encoding.length)) { + System.arraycopy(utf8encoding, 0, utf8encoding = new byte[Math.min(utf8encodingLength + 100, 65535)], 0, length); + } + if ((current >= 0x0001) && (current <= 0x007F)) { + // we only need one byte: ASCII table + utf8encoding[length++] = (byte) current; + } else { + if (current > 0x07FF) { + // we need 3 bytes + utf8encoding[length++] = (byte) (0xE0 | ((current >> 12) & 0x0F)); // 0xE0 = 1110 0000 + utf8encoding[length++] = (byte) (0x80 | ((current >> 6) & 0x3F)); // 0x80 = 1000 0000 + utf8encoding[length++] = (byte) (0x80 | (current & 0x3F)); // 0x80 = 1000 0000 + } else { + // we can be 0 or between 0x0080 and 0x07FF + // In that case we only need 2 bytes + utf8encoding[length++] = (byte) (0xC0 | ((current >> 6) & 0x1F)); // 0xC0 = 1100 0000 + utf8encoding[length++] = (byte) (0x80 | (current & 0x3F)); // 0x80 = 1000 0000 + } + } + i++; + } + // the next part is done + subChars = new char[i - startIndex]; + System.arraycopy(constantChars, startIndex, subChars, 0, i - startIndex); + System.arraycopy(utf8encoding, 0, utf8encoding = new byte[length], 0, length); + index = constantPool.literalIndex(subChars, utf8encoding); + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (index > 255) { + // Generate a ldc_w + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_ldc_w; + writeUnsignedShort(index); + } else { + // Generate a ldc + if (classFileOffset + 1 >= bCodeStream.length) { + resizeByteArray(); + } + position += 2; + bCodeStream[classFileOffset++] = OPC_ldc; + bCodeStream[classFileOffset++] = (byte) index; + } + // now on the stack it should be a StringBuffer and a string. + invokeStringBufferAppendForType(T_String); + } + invokeStringBufferToString(); + invokeStringIntern(); + } +} +final public void ldc2_w(double constant) { + if (DEBUG) System.out.println(position + "\t\tldc2_w:"+constant); //$NON-NLS-1$ + countLabels = 0; + int index = constantPool.literalIndex(constant); + stackDepth += 2; + if (stackDepth > stackMax) + stackMax = stackDepth; + // Generate a ldc2_w + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_ldc2_w; + writeUnsignedShort(index); +} +final public void ldc2_w(long constant) { + if (DEBUG) System.out.println(position + "\t\tldc2_w:"+constant); //$NON-NLS-1$ + countLabels = 0; + int index = constantPool.literalIndex(constant); + stackDepth += 2; + if (stackDepth > stackMax) + stackMax = stackDepth; + // Generate a ldc2_w + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_ldc2_w; + writeUnsignedShort(index); +} +final public void ldiv() { + if (DEBUG) System.out.println(position + "\t\tldiv"); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 2; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_ldiv; +} +final public void lload(int iArg) { + if (DEBUG) System.out.println(position + "\t\tlload:"+iArg); //$NON-NLS-1$ + countLabels = 0; + stackDepth += 2; + if (maxLocals <= iArg + 1) { + maxLocals = iArg + 2; + } + if (stackDepth > stackMax) + stackMax = stackDepth; + if (iArg > 255) { // Widen + if (classFileOffset + 3 >= bCodeStream.length) { + resizeByteArray(); + } + position += 2; + bCodeStream[classFileOffset++] = OPC_wide; + bCodeStream[classFileOffset++] = OPC_lload; + writeUnsignedShort(iArg); + } else { + if (classFileOffset + 1 >= bCodeStream.length) { + resizeByteArray(); + } + position += 2; + bCodeStream[classFileOffset++] = OPC_lload; + bCodeStream[classFileOffset++] = (byte) iArg; + } +} +final public void lload_0() { + if (DEBUG) System.out.println(position + "\t\tlload_0"); //$NON-NLS-1$ + countLabels = 0; + stackDepth += 2; + if (maxLocals < 2) { + maxLocals = 2; + } + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_lload_0; +} +final public void lload_1() { + if (DEBUG) System.out.println(position + "\t\tlload_1"); //$NON-NLS-1$ + countLabels = 0; + stackDepth += 2; + if (maxLocals < 3) { + maxLocals = 3; + } + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_lload_1; +} +final public void lload_2() { + if (DEBUG) System.out.println(position + "\t\tlload_2"); //$NON-NLS-1$ + countLabels = 0; + stackDepth += 2; + if (maxLocals < 4) { + maxLocals = 4; + } + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_lload_2; +} +final public void lload_3() { + if (DEBUG) System.out.println(position + "\t\tlload_3"); //$NON-NLS-1$ + countLabels = 0; + stackDepth += 2; + if (maxLocals < 5) { + maxLocals = 5; + } + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_lload_3; +} +final public void lmul() { + if (DEBUG) System.out.println(position + "\t\tlmul"); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 2; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_lmul; +} +final public void lneg() { + if (DEBUG) System.out.println(position + "\t\tlneg"); //$NON-NLS-1$ + countLabels = 0; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_lneg; +} +public final void load(LocalVariableBinding localBinding) { + countLabels = 0; + TypeBinding typeBinding = localBinding.type; + int resolvedPosition = localBinding.resolvedPosition; + // Using dedicated int bytecode + if (typeBinding == IntBinding) { + switch (resolvedPosition) { + case 0 : + this.iload_0(); + break; + case 1 : + this.iload_1(); + break; + case 2 : + this.iload_2(); + break; + case 3 : + this.iload_3(); + break; + //case -1 : + // internal failure: trying to load variable not supposed to be generated + // break; + default : + this.iload(resolvedPosition); + } + return; + } + // Using dedicated float bytecode + if (typeBinding == FloatBinding) { + switch (resolvedPosition) { + case 0 : + this.fload_0(); + break; + case 1 : + this.fload_1(); + break; + case 2 : + this.fload_2(); + break; + case 3 : + this.fload_3(); + break; + default : + this.fload(resolvedPosition); + } + return; + } + // Using dedicated long bytecode + if (typeBinding == LongBinding) { + switch (resolvedPosition) { + case 0 : + this.lload_0(); + break; + case 1 : + this.lload_1(); + break; + case 2 : + this.lload_2(); + break; + case 3 : + this.lload_3(); + break; + default : + this.lload(resolvedPosition); + } + return; + } + // Using dedicated double bytecode + if (typeBinding == DoubleBinding) { + switch (resolvedPosition) { + case 0 : + this.dload_0(); + break; + case 1 : + this.dload_1(); + break; + case 2 : + this.dload_2(); + break; + case 3 : + this.dload_3(); + break; + default : + this.dload(resolvedPosition); + } + return; + } + // boolean, byte, char and short are handled as int + if ((typeBinding == ByteBinding) || (typeBinding == CharBinding) || (typeBinding == BooleanBinding) || (typeBinding == ShortBinding)) { + switch (resolvedPosition) { + case 0 : + this.iload_0(); + break; + case 1 : + this.iload_1(); + break; + case 2 : + this.iload_2(); + break; + case 3 : + this.iload_3(); + break; + default : + this.iload(resolvedPosition); + } + return; + } + + // Reference object + switch (resolvedPosition) { + case 0 : + this.aload_0(); + break; + case 1 : + this.aload_1(); + break; + case 2 : + this.aload_2(); + break; + case 3 : + this.aload_3(); + break; + default : + this.aload(resolvedPosition); + } +} +public final void load(TypeBinding typeBinding, int resolvedPosition) { + countLabels = 0; + // Using dedicated int bytecode + if (typeBinding == IntBinding) { + switch (resolvedPosition) { + case 0 : + this.iload_0(); + break; + case 1 : + this.iload_1(); + break; + case 2 : + this.iload_2(); + break; + case 3 : + this.iload_3(); + break; + default : + this.iload(resolvedPosition); + } + return; + } + // Using dedicated float bytecode + if (typeBinding == FloatBinding) { + switch (resolvedPosition) { + case 0 : + this.fload_0(); + break; + case 1 : + this.fload_1(); + break; + case 2 : + this.fload_2(); + break; + case 3 : + this.fload_3(); + break; + default : + this.fload(resolvedPosition); + } + return; + } + // Using dedicated long bytecode + if (typeBinding == LongBinding) { + switch (resolvedPosition) { + case 0 : + this.lload_0(); + break; + case 1 : + this.lload_1(); + break; + case 2 : + this.lload_2(); + break; + case 3 : + this.lload_3(); + break; + default : + this.lload(resolvedPosition); + } + return; + } + // Using dedicated double bytecode + if (typeBinding == DoubleBinding) { + switch (resolvedPosition) { + case 0 : + this.dload_0(); + break; + case 1 : + this.dload_1(); + break; + case 2 : + this.dload_2(); + break; + case 3 : + this.dload_3(); + break; + default : + this.dload(resolvedPosition); + } + return; + } + // boolean, byte, char and short are handled as int + if ((typeBinding == ByteBinding) || (typeBinding == CharBinding) || (typeBinding == BooleanBinding) || (typeBinding == ShortBinding)) { + switch (resolvedPosition) { + case 0 : + this.iload_0(); + break; + case 1 : + this.iload_1(); + break; + case 2 : + this.iload_2(); + break; + case 3 : + this.iload_3(); + break; + default : + this.iload(resolvedPosition); + } + return; + } + + // Reference object + switch (resolvedPosition) { + case 0 : + this.aload_0(); + break; + case 1 : + this.aload_1(); + break; + case 2 : + this.aload_2(); + break; + case 3 : + this.aload_3(); + break; + default : + this.aload(resolvedPosition); + } +} +public final void loadInt(int resolvedPosition) { + // Using dedicated int bytecode + switch (resolvedPosition) { + case 0 : + this.iload_0(); + break; + case 1 : + this.iload_1(); + break; + case 2 : + this.iload_2(); + break; + case 3 : + this.iload_3(); + break; + default : + this.iload(resolvedPosition); + } +} +public final void loadObject(int resolvedPosition) { + switch (resolvedPosition) { + case 0 : + this.aload_0(); + break; + case 1 : + this.aload_1(); + break; + case 2 : + this.aload_2(); + break; + case 3 : + this.aload_3(); + break; + default : + this.aload(resolvedPosition); + } +} +final public void lookupswitch(CaseLabel defaultLabel, int[] keys, int[] sortedIndexes, CaseLabel[] casesLabel) { + if (DEBUG) System.out.println(position + "\t\tlookupswitch"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + int length = keys.length; + int pos = position; + defaultLabel.placeInstruction(); + for (int i = 0; i < length; i++) { + casesLabel[i].placeInstruction(); + } + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_lookupswitch; + for (int i = (3 - (pos % 4)); i > 0; i--) { + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = 0; + } + defaultLabel.branch(); + writeSignedWord(length); + for (int i = 0; i < length; i++) { + writeSignedWord(keys[sortedIndexes[i]]); + casesLabel[sortedIndexes[i]].branch(); + } +} +final public void lor() { + if (DEBUG) System.out.println(position + "\t\tlor"); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 2; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_lor; +} +final public void lrem() { + if (DEBUG) System.out.println(position + "\t\tlrem"); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 2; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_lrem; +} +final public void lreturn() { + if (DEBUG) System.out.println(position + "\t\tlreturn"); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 2; + // the stackDepth should be equal to 0 + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_lreturn; +} +final public void lshl() { + if (DEBUG) System.out.println(position + "\t\tlshl"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_lshl; +} +final public void lshr() { + if (DEBUG) System.out.println(position + "\t\tlshr"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_lshr; +} +final public void lstore(int iArg) { + if (DEBUG) System.out.println(position + "\t\tlstore:"+iArg); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 2; + if (maxLocals <= iArg + 1) { + maxLocals = iArg + 2; + } + if (iArg > 255) { // Widen + if (classFileOffset + 3 >= bCodeStream.length) { + resizeByteArray(); + } + position += 2; + bCodeStream[classFileOffset++] = OPC_wide; + bCodeStream[classFileOffset++] = OPC_lstore; + writeUnsignedShort(iArg); + } else { + if (classFileOffset + 1 >= bCodeStream.length) { + resizeByteArray(); + } + position += 2; + bCodeStream[classFileOffset++] = OPC_lstore; + bCodeStream[classFileOffset++] = (byte) iArg; + } +} +final public void lstore_0() { + if (DEBUG) System.out.println(position + "\t\tlstore_0"); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 2; + if (maxLocals < 2) { + maxLocals = 2; + } + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_lstore_0; +} +final public void lstore_1() { + if (DEBUG) System.out.println(position + "\t\tlstore_1"); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 2; + if (maxLocals < 3) { + maxLocals = 3; + } + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_lstore_1; +} +final public void lstore_2() { + if (DEBUG) System.out.println(position + "\t\tlstore_2"); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 2; + if (maxLocals < 4) { + maxLocals = 4; + } + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_lstore_2; +} +final public void lstore_3() { + if (DEBUG) System.out.println(position + "\t\tlstore_3"); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 2; + if (maxLocals < 5) { + maxLocals = 5; + } + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_lstore_3; +} +final public void lsub() { + if (DEBUG) System.out.println(position + "\t\tlsub"); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 2; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_lsub; +} +final public void lushr() { + if (DEBUG) System.out.println(position + "\t\tlushr"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_lushr; +} +final public void lxor() { + if (DEBUG) System.out.println(position + "\t\tlxor"); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 2; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_lxor; +} +final public void monitorenter() { + if (DEBUG) System.out.println(position + "\t\tmonitorenter"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_monitorenter; +} +final public void monitorexit() { + if (DEBUG) System.out.println(position + "\t\tmonitorexit"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_monitorexit; +} +final public void multianewarray(TypeBinding typeBinding, int dimensions) { + if (DEBUG) System.out.println(position + "\t\tmultinewarray:"+typeBinding+","+dimensions); //$NON-NLS-1$ //$NON-NLS-2$ + countLabels = 0; + stackDepth += (1 - dimensions); + if (classFileOffset + 3 >= bCodeStream.length) { + resizeByteArray(); + } + position += 2; + bCodeStream[classFileOffset++] = OPC_multianewarray; + writeUnsignedShort(constantPool.literalIndex(typeBinding)); + bCodeStream[classFileOffset++] = (byte) dimensions; +} +/** + * We didn't call it new, because there is a conflit with the new keyword + */ +final public void new_(TypeBinding typeBinding) { + if (DEBUG) System.out.println(position + "\t\tnew:"+typeBinding); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_new; + writeUnsignedShort(constantPool.literalIndex(typeBinding)); +} +final public void newarray(int array_Type) { + if (DEBUG) System.out.println(position + "\t\tnewarray:"+array_Type); //$NON-NLS-1$ + countLabels = 0; + if (classFileOffset + 1 >= bCodeStream.length) { + resizeByteArray(); + } + position += 2; + bCodeStream[classFileOffset++] = OPC_newarray; + bCodeStream[classFileOffset++] = (byte) array_Type; +} +public void newArray(Scope scope, ArrayBinding arrayBinding) { + TypeBinding component = arrayBinding.elementsType(scope); + switch (component.id) { + case T_int : + this.newarray(10); + break; + case T_byte : + this.newarray(8); + break; + case T_boolean : + this.newarray(4); + break; + case T_short : + this.newarray(9); + break; + case T_char : + this.newarray(5); + break; + case T_long : + this.newarray(11); + break; + case T_float : + this.newarray(6); + break; + case T_double : + this.newarray(7); + break; + default : + this.anewarray(component); + } +} +public void newJavaLangError() { + // new: java.lang.Error + if (DEBUG) System.out.println(position + "\t\tnew: java.lang.Error"); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_new; + writeUnsignedShort(constantPool.literalIndexForJavaLangError()); +} + +public void newJavaLangAssertionError() { + // new: java.lang.AssertionError + if (DEBUG) System.out.println(position + "\t\tnew: java.lang.AssertionError"); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_new; + writeUnsignedShort(constantPool.literalIndexForJavaLangAssertionError()); +} + +public void newNoClassDefFoundError() { + // new: java.lang.NoClassDefFoundError + if (DEBUG) System.out.println(position + "\t\tnew: java.lang.NoClassDefFoundError"); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_new; + writeUnsignedShort(constantPool.literalIndexForJavaLangNoClassDefFoundError()); +} +public void newStringBuffer() { + // new: java.lang.StringBuffer + if (DEBUG) System.out.println(position + "\t\tnew: java.lang.StringBuffer"); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_new; + writeUnsignedShort(constantPool.literalIndexForJavaLangStringBuffer()); +} +public void newWrapperFor(int typeID) { + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_new; + switch (typeID) { + case T_int : // new: java.lang.Integer + if (DEBUG) System.out.println(position + "\t\tnew: java.lang.Integer"); //$NON-NLS-1$ + writeUnsignedShort(constantPool.literalIndexForJavaLangInteger()); + break; + case T_boolean : // new: java.lang.Boolean + if (DEBUG) System.out.println(position + "\t\tnew: java.lang.Boolean"); //$NON-NLS-1$ + writeUnsignedShort(constantPool.literalIndexForJavaLangBoolean()); + break; + case T_byte : // new: java.lang.Byte + if (DEBUG) System.out.println(position + "\t\tnew: java.lang.Byte"); //$NON-NLS-1$ + writeUnsignedShort(constantPool.literalIndexForJavaLangByte()); + break; + case T_char : // new: java.lang.Character + if (DEBUG) System.out.println(position + "\t\tnew: java.lang.Character"); //$NON-NLS-1$ + writeUnsignedShort(constantPool.literalIndexForJavaLangCharacter()); + break; + case T_float : // new: java.lang.Float + if (DEBUG) System.out.println(position + "\t\tnew: java.lang.Float"); //$NON-NLS-1$ + writeUnsignedShort(constantPool.literalIndexForJavaLangFloat()); + break; + case T_double : // new: java.lang.Double + if (DEBUG) System.out.println(position + "\t\tnew: java.lang.Double"); //$NON-NLS-1$ + writeUnsignedShort(constantPool.literalIndexForJavaLangDouble()); + break; + case T_short : // new: java.lang.Short + if (DEBUG) System.out.println(position + "\t\tnew: java.lang.Short"); //$NON-NLS-1$ + writeUnsignedShort(constantPool.literalIndexForJavaLangShort()); + break; + case T_long : // new: java.lang.Long + if (DEBUG) System.out.println(position + "\t\tnew: java.lang.Long"); //$NON-NLS-1$ + writeUnsignedShort(constantPool.literalIndexForJavaLangLong()); + break; + case T_void : // new: java.lang.Void + if (DEBUG) System.out.println(position + "\t\tnew: java.lang.Void"); //$NON-NLS-1$ + writeUnsignedShort(constantPool.literalIndexForJavaLangVoid()); + } +} +final public void nop() { + if (DEBUG) System.out.println(position + "\t\tnop"); //$NON-NLS-1$ + countLabels = 0; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_nop; +} +final public void pop() { + if (DEBUG) System.out.println(position + "\t\tpop"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_pop; +} +final public void pop2() { + if (DEBUG) System.out.println(position + "\t\tpop2"); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 2; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_pop2; +} +final public void putfield(FieldBinding fieldBinding) { + if (DEBUG) System.out.println(position + "\t\tputfield:"+fieldBinding); //$NON-NLS-1$ + countLabels = 0; + int id; + if (((id = fieldBinding.type.id) == T_double) || (id == T_long)) + stackDepth -= 3; + else + stackDepth -= 2; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_putfield; + writeUnsignedShort(constantPool.literalIndex(fieldBinding)); +} +final public void putstatic(FieldBinding fieldBinding) { + if (DEBUG) System.out.println(position + "\t\tputstatic:"+fieldBinding); //$NON-NLS-1$ + countLabels = 0; + int id; + if (((id = fieldBinding.type.id) == T_double) || (id == T_long)) + stackDepth -= 2; + else + stackDepth -= 1; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset + 2 >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_putstatic; + writeUnsignedShort(constantPool.literalIndex(fieldBinding)); +} +public void record(LocalVariableBinding local) { + if (!generateLocalVariableTableAttributes) + return; + if (allLocalsCounter == locals.length) { + // resize the collection + System.arraycopy(locals, 0, locals = new LocalVariableBinding[allLocalsCounter + LOCALS_INCREMENT], 0, allLocalsCounter); + } + locals[allLocalsCounter++] = local; + local.initializationPCs = new int[4]; + local.initializationCount = 0; +} +public void recordPositionsFrom(int startPC, int sourcePos) { + + /* Record positions in the table, only if nothing has + * already been recorded. Since we output them on the way + * up (children first for more specific info) + * The pcToSourceMap table is always sorted. + */ + + if (!generateLineNumberAttributes) + return; + if (sourcePos == 0) + return; + + // no code generated for this node. e.g. field without any initialization + if (position == startPC) + return; + + // Widening an existing entry that already has the same source positions + if (pcToSourceMapSize + 4 > pcToSourceMap.length) { + // resize the array pcToSourceMap + System.arraycopy(pcToSourceMap, 0, pcToSourceMap = new int[pcToSourceMapSize << 1], 0, pcToSourceMapSize); + } + int newLine = ClassFile.searchLineNumber(lineSeparatorPositions, sourcePos); + // lastEntryPC represents the endPC of the lastEntry. + if (pcToSourceMapSize > 0) { + // in this case there is already an entry in the table + if (pcToSourceMap[pcToSourceMapSize - 1] != newLine) { + if (startPC < lastEntryPC) { + // we forgot to add an entry. + // search if an existing entry exists for startPC + int insertionIndex = insertionIndex(pcToSourceMap, pcToSourceMapSize, startPC); + if (insertionIndex != -1) { + // there is no existing entry starting with startPC. + int existingEntryIndex = indexOfSameLineEntrySincePC(startPC, newLine); // index for PC + /* the existingEntryIndex corresponds to en entry with the same line and a PC >= startPC. + in this case it is relevant to widen this entry instead of creating a new one. + line1: this(a, + b, + c); + with this code we generate each argument. We generate a aload0 to invoke the constructor. There is no entry for this + aload0 bytecode. The first entry is the one for the argument a. + But we want the constructor call to start at the aload0 pc and not just at the pc of the first argument. + So we widen the existing entry (if there is one) or we create a new entry with the startPC. + */ + if (existingEntryIndex != -1) { + // widen existing entry + pcToSourceMap[existingEntryIndex] = startPC; + } else { + // we have to add an entry that won't be sorted. So we sort the pcToSourceMap. + System.arraycopy(pcToSourceMap, insertionIndex, pcToSourceMap, insertionIndex + 2, pcToSourceMapSize - insertionIndex); + pcToSourceMap[insertionIndex++] = startPC; + pcToSourceMap[insertionIndex] = newLine; + pcToSourceMapSize += 2; + } + } + if (position != lastEntryPC) { // no bytecode since last entry pc + pcToSourceMap[pcToSourceMapSize++] = lastEntryPC; + pcToSourceMap[pcToSourceMapSize++] = newLine; + } + } else { + // we can safely add the new entry. The endPC of the previous entry is not in conflit with the startPC of the new entry. + pcToSourceMap[pcToSourceMapSize++] = startPC; + pcToSourceMap[pcToSourceMapSize++] = newLine; + } + } else { + /* the last recorded entry is on the same line. But it could be relevant to widen this entry. + we want to extend this entry forward in case we generated some bytecode before the last entry that are not related to any statement + */ + if (startPC < pcToSourceMap[pcToSourceMapSize - 2]) { + int insertionIndex = insertionIndex(pcToSourceMap, pcToSourceMapSize, startPC); + if (insertionIndex != -1) { + // widen the existing entry + // we have to figure out if we need to move the last entry at another location to keep a sorted table + /* First we need to check if at the insertion position there is not an existing entry + * that includes the one we want to insert. This is the case if pcToSourceMap[insertionIndex - 1] == newLine. + * In this case we don't want to change the table. If not, we want to insert a new entry. Prior to insertion + * we want to check if it is worth doing an arraycopy. If not we simply update the recorded pc. + */ + if (!((insertionIndex > 1) && (pcToSourceMap[insertionIndex - 1] == newLine))) { + if ((pcToSourceMapSize > 4) && (pcToSourceMap[pcToSourceMapSize - 4] > startPC)) { + System.arraycopy(pcToSourceMap, insertionIndex, pcToSourceMap, insertionIndex + 2, pcToSourceMapSize - 2 - insertionIndex); + pcToSourceMap[insertionIndex++] = startPC; + pcToSourceMap[insertionIndex] = newLine; + } else { + pcToSourceMap[pcToSourceMapSize - 2] = startPC; + } + } + } + } + } + lastEntryPC = position; + } else { + // record the first entry + pcToSourceMap[pcToSourceMapSize++] = startPC; + pcToSourceMap[pcToSourceMapSize++] = newLine; + lastEntryPC = position; + } +} +/** + * @param anExceptionLabel org.eclipse.jdt.internal.compiler.codegen.ExceptionLabel + */ +public void registerExceptionHandler(ExceptionLabel anExceptionLabel) { + int length; + if (exceptionHandlersNumber >= (length = exceptionHandlers.length)) { + // resize the exception handlers table + System.arraycopy(exceptionHandlers, 0, exceptionHandlers = new ExceptionLabel[length + LABELS_INCREMENT], 0, length); + } + // no need to resize. So just add the new exception label + exceptionHandlers[exceptionHandlersNumber++] = anExceptionLabel; +} +public final void removeNotDefinitelyAssignedVariables(Scope scope, int initStateIndex) { + // given some flow info, make sure we did not loose some variables initialization + // if this happens, then we must update their pc entries to reflect it in debug attributes + if (!generateLocalVariableTableAttributes) + return; +/* if (initStateIndex == lastInitStateIndexWhenRemovingInits) + return; + + lastInitStateIndexWhenRemovingInits = initStateIndex; + if (lastInitStateIndexWhenAddingInits != initStateIndex){ + lastInitStateIndexWhenAddingInits = -2;// reinitialize add index + // add(1)-remove(1)-add(1) -> ignore second add + // add(1)-remove(2)-add(1) -> perform second add + }*/ + for (int i = 0; i < visibleLocalsCount; i++) { + LocalVariableBinding localBinding = visibleLocals[i]; + if (localBinding != null) { + if (initStateIndex == -1 || !isDefinitelyAssigned(scope, initStateIndex, localBinding)) { + if (localBinding.initializationCount > 0) { + localBinding.recordInitializationEndPC(position); + } + } + } + } +} +/** + * @param referenceMethod org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration + * @param targetClassFile org.eclipse.jdt.internal.compiler.codegen.ClassFile + */ +public void reset(AbstractMethodDeclaration referenceMethod, ClassFile targetClassFile) { + init(targetClassFile); + this.methodDeclaration = referenceMethod; + preserveUnusedLocals = referenceMethod.scope.problemReporter().options.preserveAllLocalVariables; + initializeMaxLocals(referenceMethod.binding); +} +/** + * @param targetClassFile The given classfile to reset the code stream + */ +public void resetForProblemClinit(ClassFile targetClassFile) { + init(targetClassFile); + maxLocals = 0; +} +private final void resizeByteArray() { + int length = bCodeStream.length; + int requiredSize = length + length; + if (classFileOffset > requiredSize) { + // must be sure to grow by enough + requiredSize = classFileOffset + length; + } + System.arraycopy(bCodeStream, 0, bCodeStream = new byte[requiredSize], 0, length); +} +final public void ret(int index) { + if (DEBUG) System.out.println(position + "\t\tret:"+index); //$NON-NLS-1$ + countLabels = 0; + if (index > 255) { // Widen + if (classFileOffset + 3 >= bCodeStream.length) { + resizeByteArray(); + } + position += 2; + bCodeStream[classFileOffset++] = OPC_wide; + bCodeStream[classFileOffset++] = OPC_ret; + writeUnsignedShort(index); + } else { // Don't Widen + if (classFileOffset + 1 >= bCodeStream.length) { + resizeByteArray(); + } + position += 2; + bCodeStream[classFileOffset++] = OPC_ret; + bCodeStream[classFileOffset++] = (byte) index; + } +} +final public void return_() { + if (DEBUG) System.out.println(position + "\t\treturn"); //$NON-NLS-1$ + countLabels = 0; + // the stackDepth should be equal to 0 + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_return; +} +final public void saload() { + if (DEBUG) System.out.println(position + "\t\tsaload"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_saload; +} +final public void sastore() { + if (DEBUG) System.out.println(position + "\t\tsastore"); //$NON-NLS-1$ + countLabels = 0; + stackDepth -= 3; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_sastore; +} +/** + * @param operatorConstant int + * @param type_ID int + */ +public void sendOperator(int operatorConstant, int type_ID) { + switch (type_ID) { + case T_int : + case T_boolean : + case T_char : + case T_byte : + case T_short : + switch (operatorConstant) { + case PLUS : + this.iadd(); + break; + case MINUS : + this.isub(); + break; + case MULTIPLY : + this.imul(); + break; + case DIVIDE : + this.idiv(); + break; + case REMAINDER : + this.irem(); + break; + case LEFT_SHIFT : + this.ishl(); + break; + case RIGHT_SHIFT : + this.ishr(); + break; + case UNSIGNED_RIGHT_SHIFT : + this.iushr(); + break; + case AND : + this.iand(); + break; + case OR : + this.ior(); + break; + case XOR : + this.ixor(); + break; + } + break; + case T_long : + switch (operatorConstant) { + case PLUS : + this.ladd(); + break; + case MINUS : + this.lsub(); + break; + case MULTIPLY : + this.lmul(); + break; + case DIVIDE : + this.ldiv(); + break; + case REMAINDER : + this.lrem(); + break; + case LEFT_SHIFT : + this.lshl(); + break; + case RIGHT_SHIFT : + this.lshr(); + break; + case UNSIGNED_RIGHT_SHIFT : + this.lushr(); + break; + case AND : + this.land(); + break; + case OR : + this.lor(); + break; + case XOR : + this.lxor(); + break; + } + break; + case T_float : + switch (operatorConstant) { + case PLUS : + this.fadd(); + break; + case MINUS : + this.fsub(); + break; + case MULTIPLY : + this.fmul(); + break; + case DIVIDE : + this.fdiv(); + break; + case REMAINDER : + this.frem(); + } + break; + case T_double : + switch (operatorConstant) { + case PLUS : + this.dadd(); + break; + case MINUS : + this.dsub(); + break; + case MULTIPLY : + this.dmul(); + break; + case DIVIDE : + this.ddiv(); + break; + case REMAINDER : + this.drem(); + } + } +} +final public void sipush(int s) { + if (DEBUG) System.out.println(position + "\t\tsipush:"+s); //$NON-NLS-1$ + countLabels = 0; + stackDepth++; + if (stackDepth > stackMax) + stackMax = stackDepth; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_sipush; + writeSignedShort(s); +} +public static final void sort(int[] tab, int lo0, int hi0, int[] result) { + int lo = lo0; + int hi = hi0; + int mid; + if (hi0 > lo0) { + /* Arbitrarily establishing partition element as the midpoint of + * the array. + */ + mid = tab[ (lo0 + hi0) / 2]; + // loop through the array until indices cross + while (lo <= hi) { + /* find the first element that is greater than or equal to + * the partition element starting from the left Index. + */ + while ((lo < hi0) && (tab[lo] < mid)) + ++lo; + /* find an element that is smaller than or equal to + * the partition element starting from the right Index. + */ + while ((hi > lo0) && (tab[hi] > mid)) + --hi; + // if the indexes have not crossed, swap + if (lo <= hi) { + swap(tab, lo, hi, result); + ++lo; + --hi; + } + } + /* If the right index has not reached the left side of array + * must now sort the left partition. + */ + if (lo0 < hi) + sort(tab, lo0, hi, result); + /* If the left index has not reached the right side of array + * must now sort the right partition. + */ + if (lo < hi0) + sort(tab, lo, hi0, result); + } +} + +public final void store(LocalVariableBinding localBinding, boolean valueRequired) { + int localPosition = localBinding.resolvedPosition; + // Using dedicated int bytecode + switch(localBinding.type.id) { + case TypeIds.T_int : + case TypeIds.T_char : + case TypeIds.T_byte : + case TypeIds.T_short : + case TypeIds.T_boolean : + if (valueRequired) + this.dup(); + switch (localPosition) { + case 0 : + this.istore_0(); + break; + case 1 : + this.istore_1(); + break; + case 2 : + this.istore_2(); + break; + case 3 : + this.istore_3(); + break; + //case -1 : + // internal failure: trying to store into variable not supposed to be generated + // break; + default : + this.istore(localPosition); + } + break; + case TypeIds.T_float : + if (valueRequired) + this.dup(); + switch (localPosition) { + case 0 : + this.fstore_0(); + break; + case 1 : + this.fstore_1(); + break; + case 2 : + this.fstore_2(); + break; + case 3 : + this.fstore_3(); + break; + default : + this.fstore(localPosition); + } + break; + case TypeIds.T_double : + if (valueRequired) + this.dup2(); + switch (localPosition) { + case 0 : + this.dstore_0(); + break; + case 1 : + this.dstore_1(); + break; + case 2 : + this.dstore_2(); + break; + case 3 : + this.dstore_3(); + break; + default : + this.dstore(localPosition); + } + break; + case TypeIds.T_long : + if (valueRequired) + this.dup2(); + switch (localPosition) { + case 0 : + this.lstore_0(); + break; + case 1 : + this.lstore_1(); + break; + case 2 : + this.lstore_2(); + break; + case 3 : + this.lstore_3(); + break; + default : + this.lstore(localPosition); + } + break; + default: + // Reference object + if (valueRequired) + this.dup(); + switch (localPosition) { + case 0 : + this.astore_0(); + break; + case 1 : + this.astore_1(); + break; + case 2 : + this.astore_2(); + break; + case 3 : + this.astore_3(); + break; + default : + this.astore(localPosition); + } + } +} +public final void store(TypeBinding type, int localPosition) { + // Using dedicated int bytecode + if ((type == IntBinding) || (type == CharBinding) || (type == ByteBinding) || (type == ShortBinding) || (type == BooleanBinding)) { + switch (localPosition) { + case 0 : + this.istore_0(); + break; + case 1 : + this.istore_1(); + break; + case 2 : + this.istore_2(); + break; + case 3 : + this.istore_3(); + break; + default : + this.istore(localPosition); + } + return; + } + // Using dedicated float bytecode + if (type == FloatBinding) { + switch (localPosition) { + case 0 : + this.fstore_0(); + break; + case 1 : + this.fstore_1(); + break; + case 2 : + this.fstore_2(); + break; + case 3 : + this.fstore_3(); + break; + default : + this.fstore(localPosition); + } + return; + } + // Using dedicated long bytecode + if (type == LongBinding) { + switch (localPosition) { + case 0 : + this.lstore_0(); + break; + case 1 : + this.lstore_1(); + break; + case 2 : + this.lstore_2(); + break; + case 3 : + this.lstore_3(); + break; + default : + this.lstore(localPosition); + } + return; + } + // Using dedicated double bytecode + if (type == DoubleBinding) { + switch (localPosition) { + case 0 : + this.dstore_0(); + break; + case 1 : + this.dstore_1(); + break; + case 2 : + this.dstore_2(); + break; + case 3 : + this.dstore_3(); + break; + default : + this.dstore(localPosition); + } + return; + } + // Reference object + switch (localPosition) { + case 0 : + this.astore_0(); + break; + case 1 : + this.astore_1(); + break; + case 2 : + this.astore_2(); + break; + case 3 : + this.astore_3(); + break; + default : + this.astore(localPosition); + } +} +public final void storeInt(int localPosition) { + switch (localPosition) { + case 0 : + this.istore_0(); + break; + case 1 : + this.istore_1(); + break; + case 2 : + this.istore_2(); + break; + case 3 : + this.istore_3(); + break; + default : + this.istore(localPosition); + } +} +public final void storeObject(int localPosition) { + switch (localPosition) { + case 0 : + this.astore_0(); + break; + case 1 : + this.astore_1(); + break; + case 2 : + this.astore_2(); + break; + case 3 : + this.astore_3(); + break; + default : + this.astore(localPosition); + } +} +final public void swap() { + if (DEBUG) System.out.println(position + "\t\tswap"); //$NON-NLS-1$ + countLabels = 0; + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_swap; +} +private static final void swap(int a[], int i, int j, int result[]) { + int T; + T = a[i]; + a[i] = a[j]; + a[j] = T; + T = result[j]; + result[j] = result[i]; + result[i] = T; +} +final public void tableswitch(CaseLabel defaultLabel, int low, int high, int[] keys, int[] sortedIndexes, CaseLabel[] casesLabel) { + if (DEBUG) System.out.println(position + "\t\ttableswitch"); //$NON-NLS-1$ + countLabels = 0; + stackDepth--; + int length = casesLabel.length; + int pos = position; + defaultLabel.placeInstruction(); + for (int i = 0; i < length; i++) + casesLabel[i].placeInstruction(); + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = OPC_tableswitch; + for (int i = (3 - (pos % 4)); i > 0; i--) { + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = 0; + } + defaultLabel.branch(); + writeSignedWord(low); + writeSignedWord(high); + int i = low, j = low; + // the index j is used to know if the index i is one of the missing entries in case of an + // optimized tableswitch + while (true) { + int index; + int key = keys[index = sortedIndexes[j - low]]; + if (key == i) { + casesLabel[index].branch(); + j++; + if (i == high) break; // if high is maxint, then avoids wrapping to minint. + } else { + defaultLabel.branch(); + } + i++; + } +} +public String toString() { + StringBuffer buffer = new StringBuffer("( position:"); //$NON-NLS-1$ + buffer.append(position); + buffer.append(",\nstackDepth:"); //$NON-NLS-1$ + buffer.append(stackDepth); + buffer.append(",\nmaxStack:"); //$NON-NLS-1$ + buffer.append(stackMax); + buffer.append(",\nmaxLocals:"); //$NON-NLS-1$ + buffer.append(maxLocals); + buffer.append(")"); //$NON-NLS-1$ + return buffer.toString(); +} +public void updateLastRecordedEndPC(int pos) { + + /* Tune positions in the table, this is due to some + * extra bytecodes being + * added to some user code (jumps). */ + /** OLD CODE + if (!generateLineNumberAttributes) + return; + pcToSourceMap[pcToSourceMapSize - 1][1] = position; + // need to update the initialization endPC in case of generation of local variable attributes. + updateLocalVariablesAttribute(pos); + */ + + if (!generateLineNumberAttributes) + return; + this.lastEntryPC = pos; + // need to update the initialization endPC in case of generation of local variable attributes. + updateLocalVariablesAttribute(pos); +} +public void updateLocalVariablesAttribute(int pos) { + // need to update the initialization endPC in case of generation of local variable attributes. + if (generateLocalVariableTableAttributes) { + for (int i = 0, max = locals.length; i < max; i++) { + LocalVariableBinding local = locals[i]; + if ((local != null) && (local.initializationCount > 0)) { + if (local.initializationPCs[((local.initializationCount - 1) << 1) + 1] == pos) { + local.initializationPCs[((local.initializationCount - 1) << 1) + 1] = position; + } + } + } + } +} +/** + * Write a signed 16 bits value into the byte array + * @param value the signed short + */ +public final void writeSignedShort(int value) { + // we keep the resize in here because it is used outside the code stream + if (classFileOffset + 1 >= bCodeStream.length) { + resizeByteArray(); + } + position += 2; + bCodeStream[classFileOffset++] = (byte) (value >> 8); + bCodeStream[classFileOffset++] = (byte) value; +} +public final void writeSignedShort(int pos, int value) { + int currentOffset = startingClassFileOffset + pos; + if (currentOffset + 1 >= bCodeStream.length) { + resizeByteArray(); + } + bCodeStream[currentOffset] = (byte) (value >> 8); + bCodeStream[currentOffset + 1] = (byte) value; +} +public final void writeSignedWord(int value) { + // we keep the resize in here because it is used outside the code stream + if (classFileOffset + 3 >= bCodeStream.length) { + resizeByteArray(); + } + position += 4; + bCodeStream[classFileOffset++] = (byte) ((value & 0xFF000000) >> 24); + bCodeStream[classFileOffset++] = (byte) ((value & 0xFF0000) >> 16); + bCodeStream[classFileOffset++] = (byte) ((value & 0xFF00) >> 8); + bCodeStream[classFileOffset++] = (byte) (value & 0xFF); +} +public final void writeSignedWord(int pos, int value) { + int currentOffset = startingClassFileOffset + pos; + if (currentOffset + 4 >= bCodeStream.length) { + resizeByteArray(); + } + bCodeStream[currentOffset++] = (byte) ((value & 0xFF000000) >> 24); + bCodeStream[currentOffset++] = (byte) ((value & 0xFF0000) >> 16); + bCodeStream[currentOffset++] = (byte) ((value & 0xFF00) >> 8); + bCodeStream[currentOffset++] = (byte) (value & 0xFF); +} +/** + * Write a unsigned 16 bits value into the byte array + * @param value the unsigned short + */ +protected final void writeUnsignedShort(int value) { + position += 2; + bCodeStream[classFileOffset++] = (byte) (value >>> 8); + bCodeStream[classFileOffset++] = (byte) value; +} +/* + * Wide conditional branch compare, improved by swapping comparison opcode + * ifeq WideTarget + * becomes + * ifne Intermediate + * gotow WideTarget + * Intermediate: + */ +public void generateWideRevertedConditionalBranch(byte revertedOpcode, Label wideTarget) { + Label intermediate = new Label(this); + if (classFileOffset >= bCodeStream.length) { + resizeByteArray(); + } + position++; + bCodeStream[classFileOffset++] = revertedOpcode; + intermediate.branch(); + this.goto_w(wideTarget); + intermediate.place(); +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/codegen/ConstantPool.java b/src/java/org/eclipse/jdt/internal/compiler/codegen/ConstantPool.java new file mode 100644 index 0000000..66a2f72 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/codegen/ConstantPool.java @@ -0,0 +1,3084 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.codegen; + +import org.eclipse.jdt.core.compiler.*; +import org.eclipse.jdt.internal.compiler.ClassFile; + +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.lookup.*; + +/** + * This type is used to store all the constant pool entries. + */ +public class ConstantPool implements ClassFileConstants, TypeIds { + public static final int DOUBLE_INITIAL_SIZE = 5; + public static final int FLOAT_INITIAL_SIZE = 3; + public static final int INT_INITIAL_SIZE = 248; + public static final int LONG_INITIAL_SIZE = 5; + public static final int UTF8_INITIAL_SIZE = 778; + public static final int STRING_INITIAL_SIZE = 761; + public static final int FIELD_INITIAL_SIZE = 156; + public static final int METHOD_INITIAL_SIZE = 236; + public static final int INTERFACE_INITIAL_SIZE = 50; + public static final int CLASS_INITIAL_SIZE = 86; + public static final int NAMEANDTYPE_INITIAL_SIZE = 272; + public static final int CONSTANTPOOL_INITIAL_SIZE = 2000; + public static final int CONSTANTPOOL_GROW_SIZE = 6000; + protected DoubleCache doubleCache; + protected FloatCache floatCache; + protected IntegerCache intCache; + protected LongCache longCache; + public CharArrayCache UTF8Cache; + protected CharArrayCache stringCache; + protected ObjectCache fieldCache; + protected ObjectCache methodCache; + protected ObjectCache interfaceMethodCache; + protected ObjectCache classCache; + protected FieldNameAndTypeCache nameAndTypeCacheForFields; + protected MethodNameAndTypeCache nameAndTypeCacheForMethods; + int[] wellKnownTypes = new int[21]; + int[] wellKnownMethods = new int[36]; + int[] wellKnownFields = new int[10]; + int[] wellKnownFieldNameAndTypes = new int[2]; + int[] wellKnownMethodNameAndTypes = new int[33]; + public byte[] poolContent; + public int currentIndex = 1; + public int currentOffset; + // predefined constant index for well known types + final static int JAVA_LANG_BOOLEAN_TYPE = 0; + final static int JAVA_LANG_BYTE_TYPE = 1; + final static int JAVA_LANG_CHARACTER_TYPE = 2; + final static int JAVA_LANG_DOUBLE_TYPE = 3; + final static int JAVA_LANG_FLOAT_TYPE = 4; + final static int JAVA_LANG_INTEGER_TYPE = 5; + final static int JAVA_LANG_LONG_TYPE = 6; + final static int JAVA_LANG_SHORT_TYPE = 7; + final static int JAVA_LANG_VOID_TYPE = 8; + final static int JAVA_LANG_CLASS_TYPE = 9; + final static int JAVA_LANG_CLASSNOTFOUNDEXCEPTION_TYPE = 10; + final static int JAVA_LANG_NOCLASSDEFFOUNDERROR_TYPE = 11; + final static int JAVA_LANG_OBJECT_TYPE = 12; + final static int JAVA_LANG_STRING_TYPE = 13; + final static int JAVA_LANG_STRINGBUFFER_TYPE = 14; + final static int JAVA_LANG_SYSTEM_TYPE = 15; + final static int JAVA_LANG_THROWABLE_TYPE = 16; + final static int JAVA_LANG_ERROR_TYPE = 17; + final static int JAVA_LANG_EXCEPTION_TYPE = 18; + final static int JAVA_LANG_REFLECT_CONSTRUCTOR_TYPE = 19; + final static int JAVA_LANG_ASSERTIONERROR_TYPE = 20; + + // predefined constant index for well known fields + final static int TYPE_BYTE_FIELD = 0; + final static int TYPE_SHORT_FIELD = 1; + final static int TYPE_CHARACTER_FIELD = 2; + final static int TYPE_INTEGER_FIELD = 3; + final static int TYPE_LONG_FIELD = 4; + final static int TYPE_FLOAT_FIELD = 5; + final static int TYPE_DOUBLE_FIELD = 6; + final static int TYPE_BOOLEAN_FIELD = 7; + final static int TYPE_VOID_FIELD = 8; + final static int OUT_SYSTEM_FIELD = 9; + // predefined constant index for well known methods + final static int FORNAME_CLASS_METHOD = 0; + final static int NOCLASSDEFFOUNDERROR_CONSTR_METHOD = 1; + final static int APPEND_INT_METHOD = 2; + final static int APPEND_FLOAT_METHOD = 3; + final static int APPEND_LONG_METHOD = 4; + final static int APPEND_OBJECT_METHOD = 5; + final static int APPEND_CHAR_METHOD = 6; + final static int APPEND_STRING_METHOD = 7; + final static int APPEND_BOOLEAN_METHOD = 8; + final static int APPEND_DOUBLE_METHOD = 9; + final static int STRINGBUFFER_STRING_CONSTR_METHOD = 10; + final static int STRINGBUFFER_DEFAULT_CONSTR_METHOD = 11; + final static int STRINGBUFFER_TOSTRING_METHOD = 12; + final static int SYSTEM_EXIT_METHOD = 13; + final static int THROWABLE_GETMESSAGE_METHOD = 14; + final static int JAVALANGERROR_CONSTR_METHOD = 15; + final static int NEWINSTANCE_CONSTRUCTOR_METHOD = 16; + final static int STRING_INTERN_METHOD = 17; + final static int VALUEOF_INT_METHOD = 18; + final static int VALUEOF_FLOAT_METHOD = 19; + final static int VALUEOF_LONG_METHOD = 20; + final static int VALUEOF_OBJECT_METHOD = 21; + final static int VALUEOF_CHAR_METHOD = 22; + final static int VALUEOF_BOOLEAN_METHOD = 23; + final static int VALUEOF_DOUBLE_METHOD = 24; + final static int ASSERTIONERROR_CONSTR_OBJECT_METHOD = 25; + final static int ASSERTIONERROR_CONSTR_INT_METHOD = 26; + final static int ASSERTIONERROR_CONSTR_LONG_METHOD = 27; + final static int ASSERTIONERROR_CONSTR_FLOAT_METHOD = 28; + final static int ASSERTIONERROR_CONSTR_DOUBLE_METHOD = 29; + final static int ASSERTIONERROR_CONSTR_BOOLEAN_METHOD = 30; + final static int ASSERTIONERROR_CONSTR_CHAR_METHOD = 31; + final static int ASSERTIONERROR_DEFAULT_CONSTR_METHOD = 32; + final static int DESIREDASSERTIONSTATUS_CLASS_METHOD = 33; + final static int GETCLASS_OBJECT_METHOD = 34; + final static int GETCOMPONENTTYPE_CLASS_METHOD = 35; + + // predefined constant index for well known name and type for fields + final static int TYPE_JAVALANGCLASS_NAME_AND_TYPE = 0; + final static int OUT_SYSTEM_NAME_AND_TYPE = 1; + // predefined constant index for well known name and type for methods + final static int FORNAME_CLASS_METHOD_NAME_AND_TYPE = 0; + final static int CONSTR_STRING_METHOD_NAME_AND_TYPE = 1; + final static int DEFAULT_CONSTR_METHOD_NAME_AND_TYPE = 2; + final static int APPEND_INT_METHOD_NAME_AND_TYPE = 3; + final static int APPEND_FLOAT_METHOD_NAME_AND_TYPE = 4; + final static int APPEND_LONG_METHOD_NAME_AND_TYPE = 5; + final static int APPEND_OBJECT_METHOD_NAME_AND_TYPE = 6; + final static int APPEND_CHAR_METHOD_NAME_AND_TYPE = 7; + final static int APPEND_STRING_METHOD_NAME_AND_TYPE = 8; + final static int APPEND_BOOLEAN_METHOD_NAME_AND_TYPE = 9; + final static int APPEND_DOUBLE_METHOD_NAME_AND_TYPE = 10; + final static int TOSTRING_METHOD_NAME_AND_TYPE = 11; + final static int EXIT_METHOD_NAME_AND_TYPE = 12; + final static int GETMESSAGE_METHOD_NAME_AND_TYPE = 13; + final static int NEWINSTANCE_METHOD_NAME_AND_TYPE = 14; + final static int INTERN_METHOD_NAME_AND_TYPE = 15; + final static int VALUEOF_INT_METHOD_NAME_AND_TYPE = 16; + final static int VALUEOF_FLOAT_METHOD_NAME_AND_TYPE = 17; + final static int VALUEOF_LONG_METHOD_NAME_AND_TYPE = 18; + final static int VALUEOF_OBJECT_METHOD_NAME_AND_TYPE = 19; + final static int VALUEOF_CHAR_METHOD_NAME_AND_TYPE = 20; + final static int VALUEOF_BOOLEAN_METHOD_NAME_AND_TYPE = 21; + final static int VALUEOF_DOUBLE_METHOD_NAME_AND_TYPE = 22; + final static int CONSTR_INT_METHOD_NAME_AND_TYPE = 23; + final static int CONSTR_LONG_METHOD_NAME_AND_TYPE = 24; + final static int CONSTR_FLOAT_METHOD_NAME_AND_TYPE = 25; + final static int CONSTR_DOUBLE_METHOD_NAME_AND_TYPE = 26; + final static int CONSTR_OBJECT_METHOD_NAME_AND_TYPE = 27; + final static int CONSTR_CHAR_METHOD_NAME_AND_TYPE = 28; + final static int CONSTR_BOOLEAN_METHOD_NAME_AND_TYPE = 29; + final static int DESIREDASSERTIONSTATUS_METHOD_NAME_AND_TYPE = 30; + final static int GETCLASS_OBJECT_METHOD_NAME_AND_TYPE = 31; + final static int GETCOMPONENTTYPE_CLASS_METHOD_NAME_AND_TYPE = 32; + + public ClassFile classFile; + +/** + * ConstantPool constructor comment. + */ +public ConstantPool(ClassFile classFile) { + this.UTF8Cache = new CharArrayCache(UTF8_INITIAL_SIZE); + this.stringCache = new CharArrayCache(STRING_INITIAL_SIZE); + this.fieldCache = new ObjectCache(FIELD_INITIAL_SIZE); + this.methodCache = new ObjectCache(METHOD_INITIAL_SIZE); + this.interfaceMethodCache = new ObjectCache(INTERFACE_INITIAL_SIZE); + this.classCache = new ObjectCache(CLASS_INITIAL_SIZE); + this.nameAndTypeCacheForMethods = new MethodNameAndTypeCache(NAMEANDTYPE_INITIAL_SIZE); + this.nameAndTypeCacheForFields = new FieldNameAndTypeCache(NAMEANDTYPE_INITIAL_SIZE); + this.poolContent = classFile.header; + this.currentOffset = classFile.headerOffset; + // currentOffset is initialized to 0 by default + this.currentIndex = 1; + this.classFile = classFile; +} +/** + * Return the content of the receiver + */ +public byte[] dumpBytes() { + System.arraycopy(poolContent, 0, (poolContent = new byte[currentOffset]), 0, currentOffset); + return poolContent; +} +/** + * Return the index of the @fieldBinding. + * + * Returns -1 if the @fieldBinding is not a predefined fieldBinding, + * the right index otherwise. + * + * @param fieldBinding org.eclipse.jdt.internal.compiler.lookup.FieldBinding + * @return int + */ +public int indexOfWellKnownFieldNameAndType(FieldBinding fieldBinding) { + if ((fieldBinding.type.id == T_JavaLangClass) && (CharOperation.equals(fieldBinding.name, QualifiedNamesConstants.TYPE))) + return TYPE_JAVALANGCLASS_NAME_AND_TYPE; + if ((fieldBinding.type.id == T_JavaIoPrintStream) && (CharOperation.equals(fieldBinding.name, QualifiedNamesConstants.Out))) + return OUT_SYSTEM_NAME_AND_TYPE; + return -1; +} +/** + * Return the index of the @fieldBinding. + * + * Returns -1 if the @fieldBinding is not a predefined fieldBinding, + * the right index otherwise. + * + * @param fieldBinding org.eclipse.jdt.internal.compiler.lookup.FieldBinding + * @return int + */ +public int indexOfWellKnownFields(FieldBinding fieldBinding) { + switch (fieldBinding.declaringClass.id) { + case T_JavaLangByte : + if (CharOperation.equals(fieldBinding.name, QualifiedNamesConstants.TYPE)) + return TYPE_BYTE_FIELD; + break; + case T_JavaLangShort : + if (CharOperation.equals(fieldBinding.name, QualifiedNamesConstants.TYPE)) + return TYPE_SHORT_FIELD; + break; + case T_JavaLangCharacter : + if (CharOperation.equals(fieldBinding.name, QualifiedNamesConstants.TYPE)) + return TYPE_CHARACTER_FIELD; + break; + case T_JavaLangInteger : + if (CharOperation.equals(fieldBinding.name, QualifiedNamesConstants.TYPE)) + return TYPE_INTEGER_FIELD; + break; + case T_JavaLangLong : + if (CharOperation.equals(fieldBinding.name, QualifiedNamesConstants.TYPE)) + return TYPE_LONG_FIELD; + break; + case T_JavaLangFloat : + if (CharOperation.equals(fieldBinding.name, QualifiedNamesConstants.TYPE)) + return TYPE_FLOAT_FIELD; + break; + case T_JavaLangDouble : + if (CharOperation.equals(fieldBinding.name, QualifiedNamesConstants.TYPE)) + return TYPE_DOUBLE_FIELD; + break; + case T_JavaLangBoolean : + if (CharOperation.equals(fieldBinding.name, QualifiedNamesConstants.TYPE)) + return TYPE_BOOLEAN_FIELD; + break; + case T_JavaLangVoid : + if (CharOperation.equals(fieldBinding.name, QualifiedNamesConstants.TYPE)) + return TYPE_VOID_FIELD; + break; + case T_JavaLangSystem : + if (CharOperation.equals(fieldBinding.name, QualifiedNamesConstants.Out)) + return OUT_SYSTEM_FIELD; + } + return -1; +} +/** + * Return the index of the @methodBinding. + * + * Returns -1 if the @methodBinding is not a predefined methodBinding, + * the right index otherwise. + * + * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding + * @return int + */ +public int indexOfWellKnownMethodNameAndType(MethodBinding methodBinding) { + char firstChar = methodBinding.selector[0]; + switch (firstChar) { + case 'f' : + if ((methodBinding.parameters.length == 1) && (methodBinding.parameters[0].id == T_JavaLangString) && (methodBinding.returnType.id == T_JavaLangClass) && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.ForName))) { + // This method binding is forName(java.lang.String) + return FORNAME_CLASS_METHOD_NAME_AND_TYPE; + } + break; + case '<' : + if (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.Init)) { + switch(methodBinding.parameters.length) { + case 1: + switch(methodBinding.parameters[0].id) { + case T_String : + if (CharOperation.equals(methodBinding.signature(), QualifiedNamesConstants.StringConstructorSignature)) { + return CONSTR_STRING_METHOD_NAME_AND_TYPE; + } else { + return -1; + } + case T_Object : + if (CharOperation.equals(methodBinding.signature(), QualifiedNamesConstants.AssertionErrorObjectConstrSignature)) { + return CONSTR_OBJECT_METHOD_NAME_AND_TYPE; + } else { + return -1; + } + case T_int : + if (CharOperation.equals(methodBinding.signature(), QualifiedNamesConstants.AssertionErrorIntConstrSignature)) { + return CONSTR_INT_METHOD_NAME_AND_TYPE; + } else { + return -1; + } + case T_char : + if (CharOperation.equals(methodBinding.signature(), QualifiedNamesConstants.AssertionErrorCharConstrSignature)) { + return CONSTR_CHAR_METHOD_NAME_AND_TYPE; + } else { + return -1; + } + case T_boolean : + if (CharOperation.equals(methodBinding.signature(), QualifiedNamesConstants.AssertionErrorBooleanConstrSignature)) { + return CONSTR_BOOLEAN_METHOD_NAME_AND_TYPE; + } else { + return -1; + } + case T_float : + if (CharOperation.equals(methodBinding.signature(), QualifiedNamesConstants.AssertionErrorFloatConstrSignature)) { + return CONSTR_FLOAT_METHOD_NAME_AND_TYPE; + } else { + return -1; + } + case T_double : + if (CharOperation.equals(methodBinding.signature(), QualifiedNamesConstants.AssertionErrorDoubleConstrSignature)) { + return CONSTR_DOUBLE_METHOD_NAME_AND_TYPE; + } else { + return -1; + } + case T_long : + if (CharOperation.equals(methodBinding.signature(), QualifiedNamesConstants.AssertionErrorLongConstrSignature)) { + return CONSTR_LONG_METHOD_NAME_AND_TYPE; + } else { + return -1; + } + } + case 0: + if (methodBinding.signature().length == 3) { + return DEFAULT_CONSTR_METHOD_NAME_AND_TYPE; + } + } + } + break; + case 'a' : + if ((methodBinding.parameters.length == 1) && (methodBinding.returnType.id == T_JavaLangStringBuffer) && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.Append))) { + switch (methodBinding.parameters[0].id) { + case T_int : + case T_byte : + case T_short : + // This method binding is append(int) + return APPEND_INT_METHOD_NAME_AND_TYPE; + case T_float : + // This method binding is append(float) + return APPEND_FLOAT_METHOD_NAME_AND_TYPE; + case T_long : + // This method binding is append(long) + return APPEND_LONG_METHOD_NAME_AND_TYPE; + case T_JavaLangObject : + // This method binding is append(java.lang.Object) + return APPEND_OBJECT_METHOD_NAME_AND_TYPE; + case T_char : + // This method binding is append(char) + return APPEND_CHAR_METHOD_NAME_AND_TYPE; + case T_JavaLangString : + // This method binding is append(java.lang.String) + return APPEND_STRING_METHOD_NAME_AND_TYPE; + case T_boolean : + // This method binding is append(boolean) + return APPEND_BOOLEAN_METHOD_NAME_AND_TYPE; + case T_double : + // This method binding is append(double) + return APPEND_DOUBLE_METHOD_NAME_AND_TYPE; + } + } + break; + case 't' : + if ((methodBinding.parameters.length == 0) && (methodBinding.returnType.id == T_JavaLangString) && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.ToString))) { + // This method binding is toString() + return TOSTRING_METHOD_NAME_AND_TYPE; + } + break; + case 'v' : + if ((methodBinding.parameters.length == 1) && (methodBinding.returnType.id == T_JavaLangString) && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.ValueOf))) { + switch(methodBinding.parameters[0].id) { + case T_Object: + return VALUEOF_OBJECT_METHOD_NAME_AND_TYPE; + case T_int: + case T_short: + case T_byte: + return VALUEOF_INT_METHOD_NAME_AND_TYPE; + case T_long: + return VALUEOF_LONG_METHOD_NAME_AND_TYPE; + case T_float: + return VALUEOF_FLOAT_METHOD_NAME_AND_TYPE; + case T_double: + return VALUEOF_DOUBLE_METHOD_NAME_AND_TYPE; + case T_boolean: + return VALUEOF_BOOLEAN_METHOD_NAME_AND_TYPE; + case T_char: + return VALUEOF_CHAR_METHOD_NAME_AND_TYPE; + } + } + break; + case 'e' : + if ((methodBinding.parameters.length == 1) && (methodBinding.parameters[0].id == T_int) && (methodBinding.returnType.id == T_void) && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.Exit))) { + // This method binding is exit(int) + return EXIT_METHOD_NAME_AND_TYPE; + } + break; + case 'g' : + if ((methodBinding.selector.length == 10) + && (methodBinding.parameters.length == 0) + && (methodBinding.returnType.id == T_JavaLangString) + && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.GetMessage))) { + // This method binding is getMessage() + return GETMESSAGE_METHOD_NAME_AND_TYPE; + } + if (methodBinding.parameters.length == 0 + && methodBinding.returnType.id == T_JavaLangClass + && CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.GetClass)) { + return GETCLASS_OBJECT_METHOD_NAME_AND_TYPE; + } + if (methodBinding.parameters.length == 0 + && methodBinding.returnType.id == T_JavaLangClass + && CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.GetComponentType)) { + return GETCOMPONENTTYPE_CLASS_METHOD_NAME_AND_TYPE; + } + break; + case 'i' : + if ((methodBinding.parameters.length == 0) && (methodBinding.returnType.id == T_JavaLangString) && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.Intern))) { + // This method binding is toString() + return INTERN_METHOD_NAME_AND_TYPE; + } + } + return -1; +} +/** + * Return the index of the @methodBinding. + * + * Returns -1 if the @methodBinding is not a predefined methodBinding, + * the right index otherwise. + * + * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding + * @return int + */ +public int indexOfWellKnownMethods(MethodBinding methodBinding) { + char firstChar = methodBinding.selector[0]; + switch (methodBinding.declaringClass.id) { + case T_JavaLangClass : + if ((firstChar == 'f') && (methodBinding.isStatic()) && (methodBinding.parameters.length == 1) && (methodBinding.parameters[0].id == T_JavaLangString) && (methodBinding.returnType.id == T_JavaLangClass) && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.ForName))) { + // This method binding is forName(java.lang.String) + return FORNAME_CLASS_METHOD; + } else if ((firstChar == 'd') && (methodBinding.parameters.length == 0) && (methodBinding.returnType.id == T_boolean) && CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.DesiredAssertionStatus)) { + return DESIREDASSERTIONSTATUS_CLASS_METHOD; + } else if ((firstChar == 'g') && (methodBinding.parameters.length == 0) && (methodBinding.returnType.id == T_JavaLangClass) && CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.GetComponentType)) { + return GETCOMPONENTTYPE_CLASS_METHOD; + } + break; + case T_JavaLangNoClassDefError : + if ((firstChar == '<') && (methodBinding.parameters.length == 1) && (methodBinding.parameters[0].id == T_JavaLangString) && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.Init))) { + // This method binding is NoClassDefFoundError(java.lang.String) + return NOCLASSDEFFOUNDERROR_CONSTR_METHOD; + } + break; + case T_JavaLangReflectConstructor : + if ((firstChar == 'n') && (methodBinding.parameters.length == 1) && (methodBinding.returnType.id == T_JavaLangObject) && CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.NewInstance) && CharOperation.equals(methodBinding.parameters[0].constantPoolName(), QualifiedNamesConstants.ArrayJavaLangObjectConstantPoolName)) { + return NEWINSTANCE_CONSTRUCTOR_METHOD; + } + break; + case T_JavaLangStringBuffer : + if ((firstChar == 'a') && (methodBinding.parameters.length == 1) && (methodBinding.returnType.id == T_JavaLangStringBuffer) && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.Append))) { + switch (methodBinding.parameters[0].id) { + case T_int : + case T_byte : + case T_short : + // This method binding is append(int) + return APPEND_INT_METHOD; + case T_float : + // This method binding is append(float) + return APPEND_FLOAT_METHOD; + case T_long : + // This method binding is append(long) + return APPEND_LONG_METHOD; + case T_JavaLangObject : + // This method binding is append(java.lang.Object) + return APPEND_OBJECT_METHOD; + case T_char : + // This method binding is append(char) + return APPEND_CHAR_METHOD; + case T_JavaLangString : + // This method binding is append(java.lang.String) + return APPEND_STRING_METHOD; + case T_boolean : + // This method binding is append(boolean) + return APPEND_BOOLEAN_METHOD; + case T_double : + // This method binding is append(double) + return APPEND_DOUBLE_METHOD; + } + } else + if ((firstChar == 't') && (methodBinding.parameters.length == 0) && (methodBinding.returnType.id == T_JavaLangString) && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.ToString))) { + // This method binding is toString() + return STRINGBUFFER_TOSTRING_METHOD; + } else + if ((firstChar == '<') && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.Init))) { + if ((methodBinding.parameters.length == 1) && (methodBinding.parameters[0].id == T_JavaLangString)) { + // This method binding is (String) + return STRINGBUFFER_STRING_CONSTR_METHOD; + } else { + if (methodBinding.parameters.length == 0) { + // This method binding is () + return STRINGBUFFER_DEFAULT_CONSTR_METHOD; + } + } + } + break; + case T_JavaLangString : + if ((firstChar == 'v') && (methodBinding.parameters.length == 1) && (methodBinding.returnType.id == T_JavaLangString) && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.ValueOf))) { + // This method binding is valueOf(java.lang.Object) + switch (methodBinding.parameters[0].id) { + case T_Object : + return VALUEOF_OBJECT_METHOD; + case T_int : + case T_short : + case T_byte : + return VALUEOF_INT_METHOD; + case T_long : + return VALUEOF_LONG_METHOD; + case T_float : + return VALUEOF_FLOAT_METHOD; + case T_double : + return VALUEOF_DOUBLE_METHOD; + case T_boolean : + return VALUEOF_BOOLEAN_METHOD; + case T_char : + return VALUEOF_CHAR_METHOD; + } + } else + if ((firstChar == 'i') && (methodBinding.parameters.length == 0) && (methodBinding.returnType.id == T_JavaLangString) && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.Intern))) { + // This method binding is valueOf(java.lang.Object) + return STRING_INTERN_METHOD; + } + break; + case T_JavaLangSystem : + if ((firstChar == 'e') && (methodBinding.parameters.length == 1) && (methodBinding.parameters[0].id == T_int) && (methodBinding.returnType.id == T_void) && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.Exit))) { + // This method binding is exit(int) + return SYSTEM_EXIT_METHOD; + } + break; + case T_JavaLangThrowable : + if ((firstChar == 'g') && (methodBinding.selector.length == 10) && (methodBinding.parameters.length == 0) && (methodBinding.returnType.id == T_JavaLangString) && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.GetMessage))) { + // This method binding is getMessage() + return THROWABLE_GETMESSAGE_METHOD; + } + break; + case T_JavaLangError : + if ((firstChar == '<') && (methodBinding.parameters.length == 1) && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.Init)) && (methodBinding.parameters[0].id == T_String)) { + return JAVALANGERROR_CONSTR_METHOD; + } + break; + case T_JavaLangAssertionError : + if ((firstChar == '<') && CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.Init)) { + switch (methodBinding.parameters.length) { + case 0: + return ASSERTIONERROR_DEFAULT_CONSTR_METHOD; + case 1: + switch(methodBinding.parameters[0].id) { + case T_boolean : + return ASSERTIONERROR_CONSTR_BOOLEAN_METHOD; + case T_char : + return ASSERTIONERROR_CONSTR_CHAR_METHOD; + case T_double : + return ASSERTIONERROR_CONSTR_DOUBLE_METHOD; + case T_int : + case T_byte : + case T_short : + return ASSERTIONERROR_CONSTR_INT_METHOD; + case T_float : + return ASSERTIONERROR_CONSTR_FLOAT_METHOD; + case T_long : + return ASSERTIONERROR_CONSTR_LONG_METHOD; + default: + return ASSERTIONERROR_CONSTR_OBJECT_METHOD; + } + } + } + break; + case T_JavaLangObject : + if (methodBinding.parameters.length == 0 + && CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.GetClass)) { + return GETCLASS_OBJECT_METHOD; + } + } + return -1; +} +/** + * Return the index of the @typeBinding + * + * Returns -1 if the @typeBinding is not a predefined binding, the right index + * otherwise. + * + * @param typeBinding org.eclipse.jdt.internal.compiler.lookup.TypeBinding + * @return int + */ +public int indexOfWellKnownTypes(TypeBinding typeBinding) { + switch(typeBinding.id) { + case T_JavaLangBoolean : return JAVA_LANG_BOOLEAN_TYPE; + case T_JavaLangByte : return JAVA_LANG_BYTE_TYPE; + case T_JavaLangCharacter : return JAVA_LANG_CHARACTER_TYPE; + case T_JavaLangDouble : return JAVA_LANG_DOUBLE_TYPE; + case T_JavaLangFloat : return JAVA_LANG_FLOAT_TYPE; + case T_JavaLangInteger : return JAVA_LANG_INTEGER_TYPE; + case T_JavaLangLong : return JAVA_LANG_LONG_TYPE; + case T_JavaLangShort : return JAVA_LANG_SHORT_TYPE; + case T_JavaLangVoid : return JAVA_LANG_VOID_TYPE; + case T_JavaLangClass : return JAVA_LANG_CLASS_TYPE; + case T_JavaLangClassNotFoundException : return JAVA_LANG_CLASSNOTFOUNDEXCEPTION_TYPE; + case T_JavaLangNoClassDefError : return JAVA_LANG_NOCLASSDEFFOUNDERROR_TYPE; + case T_JavaLangObject : return JAVA_LANG_OBJECT_TYPE; + case T_JavaLangString : return JAVA_LANG_STRING_TYPE; + case T_JavaLangStringBuffer : return JAVA_LANG_STRINGBUFFER_TYPE; + case T_JavaLangSystem : return JAVA_LANG_SYSTEM_TYPE; + case T_JavaLangThrowable : return JAVA_LANG_THROWABLE_TYPE; + case T_JavaLangError : return JAVA_LANG_ERROR_TYPE; + case T_JavaLangException : return JAVA_LANG_EXCEPTION_TYPE; + case T_JavaLangReflectConstructor : return JAVA_LANG_REFLECT_CONSTRUCTOR_TYPE; + case T_JavaLangAssertionError : return JAVA_LANG_ASSERTIONERROR_TYPE; + } + return -1; +} +public int literalIndex(byte[] utf8encoding, char[] stringCharArray) { + int index; + if ((index = UTF8Cache.get(stringCharArray)) < 0) { + // The entry doesn't exit yet + index = UTF8Cache.put(stringCharArray, currentIndex); + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + currentIndex++; + // Write the tag first + writeU1(Utf8Tag); + // Then the size of the stringName array + //writeU2(utf8Constant.length); + int savedCurrentOffset = currentOffset; + int utf8encodingLength = utf8encoding.length; + if (currentOffset + 2 + utf8encodingLength >= poolContent.length) { + // we need to resize the poolContent array because we won't have + // enough space to write the length + resizePoolContents(2 + utf8encodingLength); + } + currentOffset += 2; + // add in once the whole byte array + System.arraycopy(utf8encoding, 0, poolContent, currentOffset, utf8encodingLength); + currentOffset += utf8encodingLength; + // Now we know the length that we have to write in the constant pool + // we use savedCurrentOffset to do that + poolContent[savedCurrentOffset] = (byte) (utf8encodingLength >> 8); + poolContent[savedCurrentOffset + 1] = (byte) utf8encodingLength; + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @param utf8Constant char[] + * @return int + */ +public int literalIndex(char[] utf8Constant) { + int index; + if ((index = UTF8Cache.get(utf8Constant)) < 0) { + // The entry doesn't exit yet + // Write the tag first + writeU1(Utf8Tag); + // Then the size of the stringName array + int savedCurrentOffset = currentOffset; + if (currentOffset + 2 >= poolContent.length) { + // we need to resize the poolContent array because we won't have + // enough space to write the length + resizePoolContents(2); + } + currentOffset += 2; + int length = 0; + for (int i = 0; i < utf8Constant.length; i++) { + char current = utf8Constant[i]; + if ((current >= 0x0001) && (current <= 0x007F)) { + // we only need one byte: ASCII table + writeU1(current); + length++; + } else + if (current > 0x07FF) { + // we need 3 bytes + length += 3; + writeU1(0xE0 | ((current >> 12) & 0x0F)); // 0xE0 = 1110 0000 + writeU1(0x80 | ((current >> 6) & 0x3F)); // 0x80 = 1000 0000 + writeU1(0x80 | (current & 0x3F)); // 0x80 = 1000 0000 + } else { + // we can be 0 or between 0x0080 and 0x07FF + // In that case we only need 2 bytes + length += 2; + writeU1(0xC0 | ((current >> 6) & 0x1F)); // 0xC0 = 1100 0000 + writeU1(0x80 | (current & 0x3F)); // 0x80 = 1000 0000 + } + } + if (length >= 65535) { + currentOffset = savedCurrentOffset - 1; + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceForConstant(this.classFile.referenceBinding.scope.referenceType()); + } + index = UTF8Cache.put(utf8Constant, currentIndex); + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + currentIndex++; + // Now we know the length that we have to write in the constant pool + // we use savedCurrentOffset to do that + poolContent[savedCurrentOffset] = (byte) (length >> 8); + poolContent[savedCurrentOffset + 1] = (byte) length; + } + return index; +} +public int literalIndex(char[] stringCharArray, byte[] utf8encoding) { + int index; + int stringIndex; + if ((index = stringCache.get(stringCharArray)) < 0) { + // The entry doesn't exit yet + stringIndex = literalIndex(utf8encoding, stringCharArray); + index = stringCache.put(stringCharArray, currentIndex++); + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the tag first + writeU1(StringTag); + // Then the string index + writeU2(stringIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the double + * value. If the double is not already present into the pool, it is added. The + * double cache is updated and it returns the right index. + * + * @param key double + * @return int + */ +public int literalIndex(double key) { + //Retrieve the index from the cache + // The double constant takes two indexes into the constant pool, but we only store + // the first index into the long table + int index; + // lazy initialization for base type caches + // If it is null, initialize it, otherwise use it + if (doubleCache == null) { + doubleCache = new DoubleCache(DOUBLE_INITIAL_SIZE); + } + if ((index = doubleCache.get(key)) < 0) { + index = doubleCache.put(key, currentIndex++); + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + currentIndex++; // a double needs an extra place into the constant pool + // Write the double into the constant pool + // First add the tag + writeU1(DoubleTag); + // Then add the 8 bytes representing the double + long temp = java.lang.Double.doubleToLongBits(key); + int length = poolContent.length; + if (currentOffset + 8 >= length) { + resizePoolContents(8); + } + for (int i = 0; i < 8; i++) { + poolContent[currentOffset++] = (byte) (temp >>> (56 - (i << 3))); + } + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the float + * value. If the float is not already present into the pool, it is added. The + * int cache is updated and it returns the right index. + * + * @param key float + * @return int + */ +public int literalIndex(float key) { + //Retrieve the index from the cache + int index; + // lazy initialization for base type caches + // If it is null, initialize it, otherwise use it + if (floatCache == null) { + floatCache = new FloatCache(FLOAT_INITIAL_SIZE); + } + if ((index = floatCache.get(key)) < 0) { + index = floatCache.put(key, currentIndex++); + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the float constant entry into the constant pool + // First add the tag + writeU1(FloatTag); + // Then add the 4 bytes representing the float + int temp = java.lang.Float.floatToIntBits(key); + if (currentOffset + 4 >= poolContent.length) { + resizePoolContents(4); + } + for (int i = 0; i < 4; i++) { + poolContent[currentOffset++] = (byte) (temp >>> (24 - i * 8)); + } + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the int + * value. If the int is not already present into the pool, it is added. The + * int cache is updated and it returns the right index. + * + * @param key int + * @return int + */ +public int literalIndex(int key) { + //Retrieve the index from the cache + int index; + // lazy initialization for base type caches + // If it is null, initialize it, otherwise use it + if (intCache == null) { + intCache = new IntegerCache(INT_INITIAL_SIZE); + } + if ((index = intCache.get(key)) < 0) { + index = intCache.put(key, currentIndex++); + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the integer constant entry into the constant pool + // First add the tag + writeU1(IntegerTag); + // Then add the 4 bytes representing the int + if (currentOffset + 4 >= poolContent.length) { + resizePoolContents(4); + } + for (int i = 0; i < 4; i++) { + poolContent[currentOffset++] = (byte) (key >>> (24 - i * 8)); + } + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the long + * value. If the long is not already present into the pool, it is added. The + * long cache is updated and it returns the right index. + * + * @param key long + * @return int + */ +public int literalIndex(long key) { + // Retrieve the index from the cache + // The long constant takes two indexes into the constant pool, but we only store + // the first index into the long table + int index; + // lazy initialization for base type caches + // If it is null, initialize it, otherwise use it + if (longCache == null) { + longCache = new LongCache(LONG_INITIAL_SIZE); + } + if ((index = longCache.get(key)) < 0) { + index = longCache.put(key, currentIndex++); + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + currentIndex++; // long value need an extra place into thwe constant pool + // Write the long into the constant pool + // First add the tag + writeU1(LongTag); + // Then add the 8 bytes representing the long + if (currentOffset + 8 >= poolContent.length) { + resizePoolContents(8); + } + for (int i = 0; i < 8; i++) { + poolContent[currentOffset++] = (byte) (key >>> (56 - (i << 3))); + } + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @param stringConstant java.lang.String + * @return int + */ +public int literalIndex(String stringConstant) { + int index; + char[] stringCharArray = stringConstant.toCharArray(); + if ((index = stringCache.get(stringCharArray)) < 0) { + // The entry doesn't exit yet + int stringIndex = literalIndex(stringCharArray); + index = stringCache.put(stringCharArray, currentIndex++); + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the tag first + writeU1(StringTag); + // Then the string index + writeU2(stringIndex); + } + return index; +} +/** + * This method returns the index into the constantPool + * corresponding to the field binding aFieldBinding. + * + * @param aFieldBinding FieldBinding + * @return int + */ +public int literalIndex(FieldBinding aFieldBinding) { + int index; + int nameAndTypeIndex; + int classIndex; + int indexWellKnownField; + if ((indexWellKnownField = indexOfWellKnownFields(aFieldBinding)) == -1) { + if ((index = fieldCache.get(aFieldBinding)) < 0) { + // The entry doesn't exit yet + classIndex = literalIndex(aFieldBinding.declaringClass); + nameAndTypeIndex = literalIndexForFields(literalIndex(aFieldBinding.name), literalIndex(aFieldBinding.type.signature()), aFieldBinding); + index = fieldCache.put(aFieldBinding, currentIndex++); + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(FieldRefTag); + writeU2(classIndex); + writeU2(nameAndTypeIndex); + } + } else { + if ((index = wellKnownFields[indexWellKnownField]) == 0) { + // that field need to be inserted + classIndex = literalIndex(aFieldBinding.declaringClass); + nameAndTypeIndex = literalIndexForFields(literalIndex(aFieldBinding.name), literalIndex(aFieldBinding.type.signature()), aFieldBinding); + index = wellKnownFields[indexWellKnownField] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(FieldRefTag); + writeU2(classIndex); + writeU2(nameAndTypeIndex); + } + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the + * method descriptor. It can be either an interface method reference constant + * or a method reference constant. + * Note: uses the method binding #constantPoolDeclaringClass which could be an array type + * for the array clone method (see UpdatedMethodDeclaration). + * @param aMethodBinding MethodBinding + * @return int + */ +public int literalIndex(MethodBinding aMethodBinding) { + int index; + int nameAndTypeIndex; + int classIndex; + int indexWellKnownMethod; + if ((indexWellKnownMethod = indexOfWellKnownMethods(aMethodBinding)) == -1) { + if (aMethodBinding.constantPoolDeclaringClass().isInterface()) { + // Lookinf into the interface method ref table + if ((index = interfaceMethodCache.get(aMethodBinding)) < 0) { + classIndex = literalIndex(aMethodBinding.constantPoolDeclaringClass()); + nameAndTypeIndex = literalIndexForMethods(literalIndex(aMethodBinding.constantPoolName()), literalIndex(aMethodBinding.signature()), aMethodBinding); + index = interfaceMethodCache.put(aMethodBinding, currentIndex++); + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the interface method ref constant into the constant pool + // First add the tag + writeU1(InterfaceMethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + } else { + // Lookinf into the method ref table + if ((index = methodCache.get(aMethodBinding)) < 0) { + classIndex = literalIndex(aMethodBinding.constantPoolDeclaringClass()); + nameAndTypeIndex = literalIndexForMethods(literalIndex(aMethodBinding.constantPoolName()), literalIndex(aMethodBinding.signature()), aMethodBinding); + index = methodCache.put(aMethodBinding, currentIndex++); + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + } + } else { + // This is a well known method + if ((index = wellKnownMethods[indexWellKnownMethod]) == 0) { + // this methods was not inserted yet + if (aMethodBinding.constantPoolDeclaringClass().isInterface()) { + // Lookinf into the interface method ref table + classIndex = literalIndex(aMethodBinding.constantPoolDeclaringClass()); + nameAndTypeIndex = literalIndexForMethods(literalIndex(aMethodBinding.constantPoolName()), literalIndex(aMethodBinding.signature()), aMethodBinding); + index = wellKnownMethods[indexWellKnownMethod] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the interface method ref constant into the constant pool + // First add the tag + writeU1(InterfaceMethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } else { + // Lookinf into the method ref table + classIndex = literalIndex(aMethodBinding.constantPoolDeclaringClass()); + nameAndTypeIndex = literalIndexForMethods(literalIndex(aMethodBinding.constantPoolName()), literalIndex(aMethodBinding.signature()), aMethodBinding); + index = wellKnownMethods[indexWellKnownMethod] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + } + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @param aTypeBinding TypeBinding + * @return int + */ +public int literalIndex(TypeBinding aTypeBinding) { + int index; + int nameIndex; + int indexWellKnownType; + if ((indexWellKnownType = indexOfWellKnownTypes(aTypeBinding)) == -1) { + if ((index = classCache.get(aTypeBinding)) < 0) { + // The entry doesn't exit yet + nameIndex = literalIndex(aTypeBinding.constantPoolName()); + index = classCache.put(aTypeBinding, currentIndex++); + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + } else { + if ((index = wellKnownTypes[indexWellKnownType]) == 0) { + // Need to insert that binding + nameIndex = literalIndex(aTypeBinding.constantPoolName()); + index = wellKnownTypes[indexWellKnownType] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + } + return index; +} +/** + * This method returns the index into the constantPool corresponding + * nameAndType constant with nameIndex, typeIndex. + * + * @param nameIndex int + * @param typeIndex int + * @param key org.eclipse.jdt.internal.compiler.lookup.FieldBinding + * @return int + */ +public int literalIndexForFields(int nameIndex, int typeIndex, FieldBinding key) { + int index; + int indexOfWellKnownFieldNameAndType; + if ((indexOfWellKnownFieldNameAndType = indexOfWellKnownFieldNameAndType(key)) == -1) { + // check if the entry already exists + if ((index = nameAndTypeCacheForFields.get(key)) == -1) { + // The entry doesn't exit yet + index = nameAndTypeCacheForFields.put(key, currentIndex++); + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + } else { + if ((index = wellKnownFieldNameAndTypes[indexOfWellKnownFieldNameAndType]) == 0) { + index = wellKnownFieldNameAndTypes[indexOfWellKnownFieldNameAndType] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @return int + */ +public int literalIndexForJavaLangBoolean() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_BOOLEAN_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangBooleanConstantPoolName); + index = wellKnownTypes[JAVA_LANG_BOOLEAN_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +/** + * This method returns the index into the constantPool + * corresponding to the field binding aFieldBinding. + * + * @return int + */ +public int literalIndexForJavaLangBooleanTYPE() { + int index; + if ((index = wellKnownFields[TYPE_BOOLEAN_FIELD]) == 0) { + int nameAndTypeIndex; + int classIndex; + // The entry doesn't exit yet + classIndex = literalIndexForJavaLangBoolean(); + if ((nameAndTypeIndex = wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.TYPE); + int typeIndex = literalIndex(QualifiedNamesConstants.JavaLangClassSignature); + nameAndTypeIndex = wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownFields[TYPE_BOOLEAN_FIELD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(FieldRefTag); + writeU2(classIndex); + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @return int + */ +public int literalIndexForJavaLangByte() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_BYTE_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangByteConstantPoolName); + index = wellKnownTypes[JAVA_LANG_BYTE_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +/** + * This method returns the index into the constantPool + * corresponding to the field binding aFieldBinding. + * + * @return int + */ +public int literalIndexForJavaLangByteTYPE() { + int index; + if ((index = wellKnownFields[TYPE_BYTE_FIELD]) == 0) { + int nameAndTypeIndex; + int classIndex; + // The entry doesn't exit yet + classIndex = literalIndexForJavaLangByte(); + if ((nameAndTypeIndex = wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.TYPE); + int typeIndex = literalIndex(QualifiedNamesConstants.JavaLangClassSignature); + nameAndTypeIndex = wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownFields[TYPE_BYTE_FIELD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(FieldRefTag); + writeU2(classIndex); + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @return int + */ +public int literalIndexForJavaLangCharacter() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_CHARACTER_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangCharacterConstantPoolName); + index = wellKnownTypes[JAVA_LANG_CHARACTER_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +/** + * This method returns the index into the constantPool + * corresponding to the field binding aFieldBinding. + * + * @return int + */ +public int literalIndexForJavaLangCharacterTYPE() { + int index; + if ((index = wellKnownFields[TYPE_CHARACTER_FIELD]) == 0) { + int nameAndTypeIndex; + int classIndex; + // The entry doesn't exit yet + classIndex = literalIndexForJavaLangCharacter(); + if ((nameAndTypeIndex = wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.TYPE); + int typeIndex = literalIndex(QualifiedNamesConstants.JavaLangClassSignature); + nameAndTypeIndex = wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownFields[TYPE_CHARACTER_FIELD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(FieldRefTag); + writeU2(classIndex); + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @return int + */ +public int literalIndexForJavaLangClass() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_CLASS_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangClassConstantPoolName); + index = wellKnownTypes[JAVA_LANG_CLASS_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the + * method descriptor. It can be either an interface method reference constant + * or a method reference constant. + * + * @return int + */ +public int literalIndexForJavaLangClassForName() { + int index; + int nameAndTypeIndex; + int classIndex; + // Looking into the method ref table + if ((index = wellKnownMethods[FORNAME_CLASS_METHOD]) == 0) { + classIndex = literalIndexForJavaLangClass(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[FORNAME_CLASS_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.ForName); + int typeIndex = literalIndex(QualifiedNamesConstants.ForNameSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[FORNAME_CLASS_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[FORNAME_CLASS_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the + * method descriptor. It can be either an interface method reference constant + * or a method reference constant. + * + * @return int + */ +public int literalIndexForJavaLangClassDesiredAssertionStatus() { + int index; + int nameAndTypeIndex; + int classIndex; + // Looking into the method ref table + if ((index = wellKnownMethods[DESIREDASSERTIONSTATUS_CLASS_METHOD]) == 0) { + classIndex = literalIndexForJavaLangClass(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[DESIREDASSERTIONSTATUS_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.DesiredAssertionStatus); + int typeIndex = literalIndex(QualifiedNamesConstants.DesiredAssertionStatusSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[DESIREDASSERTIONSTATUS_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[DESIREDASSERTIONSTATUS_CLASS_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the + * method descriptor. It can be either an interface method reference constant + * or a method reference constant. + * + * @return int + */ +public int literalIndexForJavaLangClassGetComponentType() { + int index; + int nameAndTypeIndex; + int classIndex; + // Looking into the method ref table + if ((index = wellKnownMethods[GETCOMPONENTTYPE_CLASS_METHOD]) == 0) { + classIndex = literalIndexForJavaLangClass(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[GETCOMPONENTTYPE_CLASS_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.GetComponentType); + int typeIndex = literalIndex(QualifiedNamesConstants.GetComponentTypeSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[GETCOMPONENTTYPE_CLASS_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[GETCOMPONENTTYPE_CLASS_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @return int + */ +public int literalIndexForJavaLangClassNotFoundException() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_CLASSNOTFOUNDEXCEPTION_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangClassNotFoundExceptionConstantPoolName); + index = wellKnownTypes[JAVA_LANG_CLASSNOTFOUNDEXCEPTION_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @return int + */ +public int literalIndexForJavaLangDouble() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_DOUBLE_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangDoubleConstantPoolName); + index = wellKnownTypes[JAVA_LANG_DOUBLE_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +/** + * This method returns the index into the constantPool + * corresponding to the field binding aFieldBinding. + * + * @return int + */ +public int literalIndexForJavaLangDoubleTYPE() { + int index; + if ((index = wellKnownFields[TYPE_DOUBLE_FIELD]) == 0) { + int nameAndTypeIndex; + int classIndex; + // The entry doesn't exit yet + classIndex = literalIndexForJavaLangDouble(); + if ((nameAndTypeIndex = wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.TYPE); + int typeIndex = literalIndex(QualifiedNamesConstants.JavaLangClassSignature); + nameAndTypeIndex = wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownFields[TYPE_DOUBLE_FIELD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(FieldRefTag); + writeU2(classIndex); + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @return int + */ +public int literalIndexForJavaLangError() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_ERROR_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangErrorConstantPoolName); + index = wellKnownTypes[JAVA_LANG_ERROR_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the + * method descriptor. It can be either an interface method reference constant + * or a method reference constant. + * + * @return int + */ +public int literalIndexForJavaLangErrorConstructor() { + int index; + int nameAndTypeIndex; + int classIndex; + // Looking into the method ref table + if ((index = wellKnownMethods[JAVALANGERROR_CONSTR_METHOD]) == 0) { + classIndex = literalIndexForJavaLangError(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_STRING_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Init); + int typeIndex = literalIndex(QualifiedNamesConstants.StringConstructorSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_STRING_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[JAVALANGERROR_CONSTR_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + return index; +} +public int literalIndexForJavaLangException() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_EXCEPTION_TYPE]) == 0) { + // The entry doesn't exit yet + int nameIndex = literalIndex(QualifiedNamesConstants.JavaLangExceptionConstantPoolName); + index = wellKnownTypes[JAVA_LANG_EXCEPTION_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @return int + */ +public int literalIndexForJavaLangFloat() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_FLOAT_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangFloatConstantPoolName); + index = wellKnownTypes[JAVA_LANG_FLOAT_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +/** + * This method returns the index into the constantPool + * corresponding to the field binding aFieldBinding. + * + * @return int + */ +public int literalIndexForJavaLangFloatTYPE() { + int index; + if ((index = wellKnownFields[TYPE_FLOAT_FIELD]) == 0) { + int nameAndTypeIndex; + int classIndex; + // The entry doesn't exit yet + classIndex = literalIndexForJavaLangFloat(); + if ((nameAndTypeIndex = wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.TYPE); + int typeIndex = literalIndex(QualifiedNamesConstants.JavaLangClassSignature); + nameAndTypeIndex = wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownFields[TYPE_FLOAT_FIELD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(FieldRefTag); + writeU2(classIndex); + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @return int + */ +public int literalIndexForJavaLangInteger() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_INTEGER_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangIntegerConstantPoolName); + index = wellKnownTypes[JAVA_LANG_INTEGER_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +/** + * This method returns the index into the constantPool + * corresponding to the field binding aFieldBinding. + * + * @return int + */ +public int literalIndexForJavaLangIntegerTYPE() { + int index; + if ((index = wellKnownFields[TYPE_INTEGER_FIELD]) == 0) { + int nameAndTypeIndex; + int classIndex; + // The entry doesn't exit yet + classIndex = literalIndexForJavaLangInteger(); + if ((nameAndTypeIndex = wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.TYPE); + int typeIndex = literalIndex(QualifiedNamesConstants.JavaLangClassSignature); + nameAndTypeIndex = wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownFields[TYPE_INTEGER_FIELD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(FieldRefTag); + writeU2(classIndex); + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @return int + */ +public int literalIndexForJavaLangLong() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_LONG_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangLongConstantPoolName); + index = wellKnownTypes[JAVA_LANG_LONG_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +/** + * This method returns the index into the constantPool + * corresponding to the field binding aFieldBinding. + * + * @return int + */ +public int literalIndexForJavaLangLongTYPE() { + int index; + if ((index = wellKnownFields[TYPE_LONG_FIELD]) == 0) { + int nameAndTypeIndex; + int classIndex; + // The entry doesn't exit yet + classIndex = literalIndexForJavaLangLong(); + if ((nameAndTypeIndex = wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.TYPE); + int typeIndex = literalIndex(QualifiedNamesConstants.JavaLangClassSignature); + nameAndTypeIndex = wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownFields[TYPE_LONG_FIELD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(FieldRefTag); + writeU2(classIndex); + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @return int + */ +public int literalIndexForJavaLangNoClassDefFoundError() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_NOCLASSDEFFOUNDERROR_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangNoClassDefFoundErrorConstantPoolName); + index = wellKnownTypes[JAVA_LANG_NOCLASSDEFFOUNDERROR_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} + +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @return int + */ +public int literalIndexForJavaLangAssertionError() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_ASSERTIONERROR_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangAssertionErrorConstantPoolName); + index = wellKnownTypes[JAVA_LANG_ASSERTIONERROR_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} + +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @param typeBindingID int + * @return int + */ +public int literalIndexForJavaLangAssertionErrorConstructor(int typeBindingID) { + int index = 0; + int nameAndTypeIndex = 0; + int classIndex = 0; + switch (typeBindingID) { + case T_int : + case T_byte : + case T_short : + if ((index = wellKnownMethods[ASSERTIONERROR_CONSTR_INT_METHOD]) == 0) { + classIndex = literalIndexForJavaLangAssertionError(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_INT_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Init); + int typeIndex = literalIndex(QualifiedNamesConstants.AssertionErrorIntConstrSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_INT_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[ASSERTIONERROR_CONSTR_INT_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + case T_long : + if ((index = wellKnownMethods[ASSERTIONERROR_CONSTR_LONG_METHOD]) == 0) { + classIndex = literalIndexForJavaLangAssertionError(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_LONG_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Init); + int typeIndex = literalIndex(QualifiedNamesConstants.AssertionErrorLongConstrSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_LONG_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[ASSERTIONERROR_CONSTR_LONG_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + case T_float : + if ((index = wellKnownMethods[ASSERTIONERROR_CONSTR_FLOAT_METHOD]) == 0) { + classIndex = literalIndexForJavaLangAssertionError(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_FLOAT_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Init); + int typeIndex = literalIndex(QualifiedNamesConstants.AssertionErrorFloatConstrSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_FLOAT_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[ASSERTIONERROR_CONSTR_FLOAT_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + case T_double : + if ((index = wellKnownMethods[ASSERTIONERROR_CONSTR_DOUBLE_METHOD]) == 0) { + classIndex = literalIndexForJavaLangAssertionError(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_DOUBLE_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Init); + int typeIndex = literalIndex(QualifiedNamesConstants.AssertionErrorDoubleConstrSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_DOUBLE_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[ASSERTIONERROR_CONSTR_DOUBLE_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + case T_char : + if ((index = wellKnownMethods[ASSERTIONERROR_CONSTR_CHAR_METHOD]) == 0) { + classIndex = literalIndexForJavaLangAssertionError(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_CHAR_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Init); + int typeIndex = literalIndex(QualifiedNamesConstants.AssertionErrorCharConstrSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_CHAR_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[ASSERTIONERROR_CONSTR_CHAR_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + case T_boolean : + if ((index = wellKnownMethods[ASSERTIONERROR_CONSTR_BOOLEAN_METHOD]) == 0) { + classIndex = literalIndexForJavaLangAssertionError(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_BOOLEAN_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Init); + int typeIndex = literalIndex(QualifiedNamesConstants.AssertionErrorBooleanConstrSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_BOOLEAN_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[ASSERTIONERROR_CONSTR_BOOLEAN_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + //case T_Object : + //case T_String : + //case T_null : + default : + if ((index = wellKnownMethods[ASSERTIONERROR_CONSTR_OBJECT_METHOD]) == 0) { + classIndex = literalIndexForJavaLangAssertionError(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_OBJECT_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Init); + int typeIndex = literalIndex(QualifiedNamesConstants.AssertionErrorObjectConstrSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_OBJECT_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[ASSERTIONERROR_CONSTR_OBJECT_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + } + return index; +} + +/** + * This method returns the index into the constantPool corresponding to the + * method descriptor. It can be either an interface method reference constant + * or a method reference constant. + * + * @return int + */ +public int literalIndexForJavaLangAssertionErrorDefaultConstructor() { + int index; + int nameAndTypeIndex; + int classIndex; + // Looking into the method ref table + if ((index = wellKnownMethods[ASSERTIONERROR_DEFAULT_CONSTR_METHOD]) == 0) { + classIndex = literalIndexForJavaLangAssertionError(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[DEFAULT_CONSTR_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Init); + int typeIndex = literalIndex(QualifiedNamesConstants.DefaultConstructorSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[DEFAULT_CONSTR_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[ASSERTIONERROR_DEFAULT_CONSTR_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + return index; +} + + +/** + * This method returns the index into the constantPool corresponding to the + * method descriptor. It can be either an interface method reference constant + * or a method reference constant. + * + * @return int + */ +public int literalIndexForJavaLangNoClassDefFoundErrorStringConstructor() { + int index; + int nameAndTypeIndex; + int classIndex; + // Looking into the method ref table + if ((index = wellKnownMethods[NOCLASSDEFFOUNDERROR_CONSTR_METHOD]) == 0) { + classIndex = literalIndexForJavaLangNoClassDefFoundError(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_STRING_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Init); + int typeIndex = literalIndex(QualifiedNamesConstants.StringConstructorSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_STRING_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[NOCLASSDEFFOUNDERROR_CONSTR_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @return int + */ +public int literalIndexForJavaLangObject() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_OBJECT_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangObjectConstantPoolName); + index = wellKnownTypes[JAVA_LANG_OBJECT_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @return int + */ +public int literalIndexForJavaLangReflectConstructor() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_REFLECT_CONSTRUCTOR_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangReflectConstructor); + index = wellKnownTypes[JAVA_LANG_REFLECT_CONSTRUCTOR_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +public int literalIndexForJavaLangReflectConstructorNewInstance() { + int index; + int nameAndTypeIndex; + int classIndex; + // Looking into the method ref table + if ((index = wellKnownMethods[NEWINSTANCE_CONSTRUCTOR_METHOD]) == 0) { + classIndex = literalIndexForJavaLangReflectConstructor(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[NEWINSTANCE_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.NewInstance); + int typeIndex = literalIndex(QualifiedNamesConstants.NewInstanceSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[NEWINSTANCE_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[NEWINSTANCE_CONSTRUCTOR_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @return int + */ +public int literalIndexForJavaLangShort() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_SHORT_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangShortConstantPoolName); + index = wellKnownTypes[JAVA_LANG_SHORT_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +/** + * This method returns the index into the constantPool + * corresponding to the field binding aFieldBinding. + * + * @return int + */ +public int literalIndexForJavaLangShortTYPE() { + int index; + if ((index = wellKnownFields[TYPE_SHORT_FIELD]) == 0) { + int nameAndTypeIndex; + int classIndex; + // The entry doesn't exit yet + classIndex = literalIndexForJavaLangShort(); + if ((nameAndTypeIndex = wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.TYPE); + int typeIndex = literalIndex(QualifiedNamesConstants.JavaLangClassSignature); + nameAndTypeIndex = wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownFields[TYPE_SHORT_FIELD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(FieldRefTag); + writeU2(classIndex); + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @return int + */ +public int literalIndexForJavaLangString() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_STRING_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangStringConstantPoolName); + index = wellKnownTypes[JAVA_LANG_STRING_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @return int + */ +public int literalIndexForJavaLangStringBuffer() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_STRINGBUFFER_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangStringBufferConstantPoolName); + index = wellKnownTypes[JAVA_LANG_STRINGBUFFER_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the + * method descriptor. It can be either an interface method reference constant + * or a method reference constant. + * + * @return int + */ +public int literalIndexForJavaLangStringBufferAppend(int typeID) { + int index = 0; + int nameAndTypeIndex = 0; + int classIndex = 0; + switch (typeID) { + case T_int : + case T_byte : + case T_short : + if ((index = wellKnownMethods[APPEND_INT_METHOD]) == 0) { + classIndex = literalIndexForJavaLangStringBuffer(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[APPEND_INT_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Append); + int typeIndex = literalIndex(QualifiedNamesConstants.AppendIntSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[APPEND_INT_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[APPEND_INT_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + case T_long : + if ((index = wellKnownMethods[APPEND_LONG_METHOD]) == 0) { + classIndex = literalIndexForJavaLangStringBuffer(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[APPEND_LONG_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Append); + int typeIndex = literalIndex(QualifiedNamesConstants.AppendLongSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[APPEND_LONG_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[APPEND_LONG_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + case T_float : + if ((index = wellKnownMethods[APPEND_FLOAT_METHOD]) == 0) { + classIndex = literalIndexForJavaLangStringBuffer(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[APPEND_FLOAT_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Append); + int typeIndex = literalIndex(QualifiedNamesConstants.AppendFloatSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[APPEND_FLOAT_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[APPEND_FLOAT_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + case T_double : + if ((index = wellKnownMethods[APPEND_DOUBLE_METHOD]) == 0) { + classIndex = literalIndexForJavaLangStringBuffer(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[APPEND_DOUBLE_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Append); + int typeIndex = literalIndex(QualifiedNamesConstants.AppendDoubleSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[APPEND_DOUBLE_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[APPEND_DOUBLE_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + case T_char : + if ((index = wellKnownMethods[APPEND_CHAR_METHOD]) == 0) { + classIndex = literalIndexForJavaLangStringBuffer(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[APPEND_CHAR_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Append); + int typeIndex = literalIndex(QualifiedNamesConstants.AppendCharSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[APPEND_CHAR_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[APPEND_CHAR_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + case T_boolean : + if ((index = wellKnownMethods[APPEND_BOOLEAN_METHOD]) == 0) { + classIndex = literalIndexForJavaLangStringBuffer(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[APPEND_BOOLEAN_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Append); + int typeIndex = literalIndex(QualifiedNamesConstants.AppendBooleanSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[APPEND_BOOLEAN_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[APPEND_BOOLEAN_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + case T_Object : + if ((index = wellKnownMethods[APPEND_OBJECT_METHOD]) == 0) { + classIndex = literalIndexForJavaLangStringBuffer(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[APPEND_OBJECT_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Append); + int typeIndex = literalIndex(QualifiedNamesConstants.AppendObjectSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[APPEND_OBJECT_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[APPEND_OBJECT_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + case T_String : + case T_null : + if ((index = wellKnownMethods[APPEND_STRING_METHOD]) == 0) { + classIndex = literalIndexForJavaLangStringBuffer(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[APPEND_STRING_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Append); + int typeIndex = literalIndex(QualifiedNamesConstants.AppendStringSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[APPEND_STRING_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[APPEND_STRING_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the + * method descriptor. It can be either an interface method reference constant + * or a method reference constant. + * + * @return int + */ +public int literalIndexForJavaLangStringBufferConstructor() { + int index; + int nameAndTypeIndex; + int classIndex; + // Looking into the method ref table + if ((index = wellKnownMethods[STRINGBUFFER_STRING_CONSTR_METHOD]) == 0) { + classIndex = literalIndexForJavaLangStringBuffer(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_STRING_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Init); + int typeIndex = literalIndex(QualifiedNamesConstants.StringConstructorSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[CONSTR_STRING_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[STRINGBUFFER_STRING_CONSTR_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the + * method descriptor. It can be either an interface method reference constant + * or a method reference constant. + * + * @return int + */ +public int literalIndexForJavaLangStringBufferDefaultConstructor() { + int index; + int nameAndTypeIndex; + int classIndex; + // Looking into the method ref table + if ((index = wellKnownMethods[STRINGBUFFER_DEFAULT_CONSTR_METHOD]) == 0) { + classIndex = literalIndexForJavaLangStringBuffer(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[DEFAULT_CONSTR_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Init); + int typeIndex = literalIndex(QualifiedNamesConstants.DefaultConstructorSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[DEFAULT_CONSTR_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[STRINGBUFFER_DEFAULT_CONSTR_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the + * method descriptor. It can be either an interface method reference constant + * or a method reference constant. + * + * @return int + */ +public int literalIndexForJavaLangStringBufferToString() { + int index; + int nameAndTypeIndex; + int classIndex; + // Looking into the method ref table + if ((index = wellKnownMethods[STRINGBUFFER_TOSTRING_METHOD]) == 0) { + classIndex = literalIndexForJavaLangStringBuffer(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[TOSTRING_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.ToString); + int typeIndex = literalIndex(QualifiedNamesConstants.ToStringSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[TOSTRING_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[STRINGBUFFER_TOSTRING_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the + * method descriptor. It can be either an interface method reference constant + * or a method reference constant. + * + * @return int + */ +public int literalIndexForJavaLangStringIntern() { + int index; + int nameAndTypeIndex; + int classIndex; + // Looking into the method ref table + if ((index = wellKnownMethods[STRING_INTERN_METHOD]) == 0) { + classIndex = literalIndexForJavaLangString(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[INTERN_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Intern); + int typeIndex = literalIndex(QualifiedNamesConstants.InternSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[INTERN_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[STRING_INTERN_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the + * method descriptor. It can be either an interface method reference constant + * or a method reference constant. + * + * @return int + */ +public int literalIndexForJavaLangStringValueOf(int typeID) { + int index = 0; + int nameAndTypeIndex = 0; + int classIndex = literalIndexForJavaLangString(); + switch (typeID) { + case T_int : + case T_byte : + case T_short : + if ((index = wellKnownMethods[VALUEOF_INT_METHOD]) == 0) { + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[VALUEOF_INT_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.ValueOf); + int typeIndex = literalIndex(QualifiedNamesConstants.ValueOfIntSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[VALUEOF_INT_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[VALUEOF_INT_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + case T_long : + if ((index = wellKnownMethods[VALUEOF_LONG_METHOD]) == 0) { + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[VALUEOF_LONG_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.ValueOf); + int typeIndex = literalIndex(QualifiedNamesConstants.ValueOfLongSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[VALUEOF_LONG_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[VALUEOF_LONG_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + case T_float : + if ((index = wellKnownMethods[VALUEOF_FLOAT_METHOD]) == 0) { + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[VALUEOF_FLOAT_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.ValueOf); + int typeIndex = literalIndex(QualifiedNamesConstants.ValueOfFloatSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[VALUEOF_FLOAT_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[VALUEOF_FLOAT_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + case T_double : + if ((index = wellKnownMethods[VALUEOF_DOUBLE_METHOD]) == 0) { + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[VALUEOF_DOUBLE_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.ValueOf); + int typeIndex = literalIndex(QualifiedNamesConstants.ValueOfDoubleSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[VALUEOF_DOUBLE_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[VALUEOF_DOUBLE_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + case T_char : + if ((index = wellKnownMethods[VALUEOF_CHAR_METHOD]) == 0) { + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[VALUEOF_CHAR_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.ValueOf); + int typeIndex = literalIndex(QualifiedNamesConstants.ValueOfCharSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[VALUEOF_CHAR_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[VALUEOF_CHAR_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + case T_boolean : + if ((index = wellKnownMethods[VALUEOF_BOOLEAN_METHOD]) == 0) { + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[VALUEOF_BOOLEAN_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.ValueOf); + int typeIndex = literalIndex(QualifiedNamesConstants.ValueOfBooleanSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[VALUEOF_BOOLEAN_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[VALUEOF_BOOLEAN_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + case T_Object : + if ((index = wellKnownMethods[VALUEOF_OBJECT_METHOD]) == 0) { + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[VALUEOF_OBJECT_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.ValueOf); + int typeIndex = literalIndex(QualifiedNamesConstants.ValueOfObjectSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[VALUEOF_OBJECT_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[VALUEOF_OBJECT_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + break; + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @return int + */ +public int literalIndexForJavaLangSystem() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_SYSTEM_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangSystemConstantPoolName); + index = wellKnownTypes[JAVA_LANG_SYSTEM_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the + * method descriptor. It can be either an interface method reference constant + * or a method reference constant. + * + * @return int + */ +public int literalIndexForJavaLangSystemExitInt() { + int index; + int nameAndTypeIndex; + int classIndex; + // Looking into the method ref table + if ((index = wellKnownMethods[SYSTEM_EXIT_METHOD]) == 0) { + classIndex = literalIndexForJavaLangSystem(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[EXIT_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Exit); + int typeIndex = literalIndex(QualifiedNamesConstants.ExitIntSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[EXIT_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[SYSTEM_EXIT_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool + * corresponding to the field binding aFieldBinding. + * + * @return int + */ +public int literalIndexForJavaLangSystemOut() { + int index; + if ((index = wellKnownFields[OUT_SYSTEM_FIELD]) == 0) { + int nameAndTypeIndex; + int classIndex; + // The entry doesn't exit yet + classIndex = literalIndexForJavaLangSystem(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[OUT_SYSTEM_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.Out); + int typeIndex = literalIndex(QualifiedNamesConstants.JavaIoPrintStreamSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[OUT_SYSTEM_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownFields[OUT_SYSTEM_FIELD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(FieldRefTag); + writeU2(classIndex); + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @return int + */ +public int literalIndexForJavaLangThrowable() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_THROWABLE_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangThrowableConstantPoolName); + index = wellKnownTypes[JAVA_LANG_THROWABLE_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the + * method descriptor. It can be either an interface method reference constant + * or a method reference constant. + * + * @return int + */ +public int literalIndexForJavaLangThrowableGetMessage() { + int index; + int nameAndTypeIndex; + int classIndex; + // Looking into the method ref table + if ((index = wellKnownMethods[THROWABLE_GETMESSAGE_METHOD]) == 0) { + classIndex = literalIndexForJavaLangThrowable(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[GETMESSAGE_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.GetMessage); + int typeIndex = literalIndex(QualifiedNamesConstants.GetMessageSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[GETMESSAGE_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[THROWABLE_GETMESSAGE_METHOD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @return int + */ +public int literalIndexForJavaLangVoid() { + int index; + if ((index = wellKnownTypes[JAVA_LANG_VOID_TYPE]) == 0) { + int nameIndex; + // The entry doesn't exit yet + nameIndex = literalIndex(QualifiedNamesConstants.JavaLangVoidConstantPoolName); + index = wellKnownTypes[JAVA_LANG_VOID_TYPE] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(ClassTag); + // Then add the 8 bytes representing the long + writeU2(nameIndex); + } + return index; +} +/** + * This method returns the index into the constantPool + * corresponding to the field binding aFieldBinding. + * + * @return int + */ +public int literalIndexForJavaLangVoidTYPE() { + int index; + if ((index = wellKnownFields[TYPE_VOID_FIELD]) == 0) { + int nameAndTypeIndex; + int classIndex; + // The entry doesn't exit yet + classIndex = literalIndexForJavaLangVoid(); + if ((nameAndTypeIndex = wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.TYPE); + int typeIndex = literalIndex(QualifiedNamesConstants.JavaLangClassSignature); + nameAndTypeIndex = wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownFields[TYPE_VOID_FIELD] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(FieldRefTag); + writeU2(classIndex); + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the type descriptor. + * + * @param stringCharArray char[] + * @return int + */ +public int literalIndexForLdc(char[] stringCharArray) { + int index; + if ((index = stringCache.get(stringCharArray)) < 0) { + int stringIndex; + // The entry doesn't exit yet + if ((stringIndex = UTF8Cache.get(stringCharArray)) < 0) { + // The entry doesn't exit yet + // Write the tag first + writeU1(Utf8Tag); + // Then the size of the stringName array + int savedCurrentOffset = currentOffset; + if (currentOffset + 2 >= poolContent.length) { + // we need to resize the poolContent array because we won't have + // enough space to write the length + resizePoolContents(2); + } + currentOffset += 2; + int length = 0; + for (int i = 0; i < stringCharArray.length; i++) { + char current = stringCharArray[i]; + if ((current >= 0x0001) && (current <= 0x007F)) { + // we only need one byte: ASCII table + writeU1(current); + length++; + } else + if (current > 0x07FF) { + // we need 3 bytes + length += 3; + writeU1(0xE0 | ((current >> 12) & 0x0F)); // 0xE0 = 1110 0000 + writeU1(0x80 | ((current >> 6) & 0x3F)); // 0x80 = 1000 0000 + writeU1(0x80 | (current & 0x3F)); // 0x80 = 1000 0000 + } else { + // we can be 0 or between 0x0080 and 0x07FF + // In that case we only need 2 bytes + length += 2; + writeU1(0xC0 | ((current >> 6) & 0x1F)); // 0xC0 = 1100 0000 + writeU1(0x80 | (current & 0x3F)); // 0x80 = 1000 0000 + } + } + if (length >= 65535) { + currentOffset = savedCurrentOffset - 1; + return -1; + } + stringIndex = UTF8Cache.put(stringCharArray, currentIndex++); + // Now we know the length that we have to write in the constant pool + // we use savedCurrentOffset to do that + if (length > 65535) { + return 0; + } + poolContent[savedCurrentOffset] = (byte) (length >> 8); + poolContent[savedCurrentOffset + 1] = (byte) length; + } + index = stringCache.put(stringCharArray, currentIndex++); + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + // Write the tag first + writeU1(StringTag); + // Then the string index + writeU2(stringIndex); + } + return index; +} +/** + * This method returns the index into the constantPool corresponding + * nameAndType constant with nameIndex, typeIndex. + * + * @param nameIndex int + * @param typeIndex int + * @param key org.eclipse.jdt.internal.compiler.lookup.MethodBinding + * @return int + */ +public int literalIndexForMethods(int nameIndex, int typeIndex, MethodBinding key) { + int index; + int indexOfWellKnownMethodNameAndType; + if ((indexOfWellKnownMethodNameAndType = indexOfWellKnownMethodNameAndType(key)) == -1) { + // check if the entry exists + if ((index = nameAndTypeCacheForMethods.get(key)) == -1) { + // The entry doesn't exit yet + index = nameAndTypeCacheForMethods.put(key, currentIndex++); + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + } else { + if ((index = wellKnownMethodNameAndTypes[indexOfWellKnownMethodNameAndType]) == 0) { + index = wellKnownMethodNameAndTypes[indexOfWellKnownMethodNameAndType] = currentIndex++; + if (index > 0xFFFF){ + this.classFile.referenceBinding.scope.problemReporter().noMoreAvailableSpaceInConstantPool(this.classFile.referenceBinding.scope.referenceType()); + } + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + } + return index; +} +/** + * This method returns the index into the constantPool corresponding to the + * method descriptor. It can be either an interface method reference constant + * or a method reference constant. + * + * @return int + */ +public int literalIndexForJavaLangObjectGetClass() { + int index; + int nameAndTypeIndex; + int classIndex; + // Looking into the method ref table + if ((index = wellKnownMethods[GETCLASS_OBJECT_METHOD]) == 0) { + classIndex = literalIndexForJavaLangObject(); + if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[GETCLASS_OBJECT_METHOD_NAME_AND_TYPE]) == 0) { + int nameIndex = literalIndex(QualifiedNamesConstants.GetClass); + int typeIndex = literalIndex(QualifiedNamesConstants.GetClassSignature); + nameAndTypeIndex = wellKnownMethodNameAndTypes[GETCLASS_OBJECT_METHOD_NAME_AND_TYPE] = currentIndex++; + writeU1(NameAndTypeTag); + writeU2(nameIndex); + writeU2(typeIndex); + } + index = wellKnownMethods[GETCLASS_OBJECT_METHOD] = currentIndex++; + // Write the method ref constant into the constant pool + // First add the tag + writeU1(MethodRefTag); + // Then write the class index + writeU2(classIndex); + // The write the nameAndType index + writeU2(nameAndTypeIndex); + } + return index; +} +/** + * This method is used to clean the receiver in case of a clinit header is generated, but the + * clinit has no code. + * This implementation assumes that the clinit is the first method to be generated. + * @see org.eclipse.jdt.internal.compiler.ast.TypeDeclaration#addClinit() + */ +public void resetForClinit(int constantPoolIndex, int constantPoolOffset) { + currentIndex = constantPoolIndex; + currentOffset = constantPoolOffset; + if (UTF8Cache.get(AttributeNamesConstants.CodeName) >= constantPoolIndex) { + UTF8Cache.remove(AttributeNamesConstants.CodeName); + } + if (UTF8Cache.get(QualifiedNamesConstants.ClinitSignature) >= constantPoolIndex) { + UTF8Cache.remove(QualifiedNamesConstants.ClinitSignature); + } + if (UTF8Cache.get(QualifiedNamesConstants.Clinit) >= constantPoolIndex) { + UTF8Cache.remove(QualifiedNamesConstants.Clinit); + } +} + +/** + * Resize the pool contents + */ +private final void resizePoolContents(int minimalSize) { + int length = poolContent.length; + int toAdd = length; + if (toAdd < minimalSize) + toAdd = minimalSize; + System.arraycopy(poolContent, 0, poolContent = new byte[length + toAdd], 0, length); +} +/** + * Write a unsigned byte into the byte array + * + * @param value int The value to write into the byte array + */ +protected final void writeU1(int value) { + if (currentOffset + 1 >= poolContent.length) { + resizePoolContents(1); + } + poolContent[currentOffset++] = (byte) value; +} +/** + * Write a unsigned byte into the byte array + * + * @param value int The value to write into the byte array + */ +protected final void writeU2(int value) { + if (currentOffset + 2 >= poolContent.length) { + resizePoolContents(2); + } + //first byte + poolContent[currentOffset++] = (byte) (value >> 8); + poolContent[currentOffset++] = (byte) value; +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/codegen/DoubleCache.java b/src/java/org/eclipse/jdt/internal/compiler/codegen/DoubleCache.java new file mode 100644 index 0000000..edb7d17 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/codegen/DoubleCache.java @@ -0,0 +1,138 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.codegen; + +public class DoubleCache { + private double keyTable[]; + private int valueTable[]; + private int elementSize; +/** + * Constructs a new, empty hashtable. A default capacity and + * load factor is used. Note that the hashtable will automatically + * grow when it gets full. + */ +public DoubleCache() { + this(13); +} +/** + * Constructs a new, empty hashtable with the specified initial + * capacity. + * @param initialCapacity int + * the initial number of buckets + */ +public DoubleCache(int initialCapacity) { + elementSize = 0; + keyTable = new double[initialCapacity]; + valueTable = new int[initialCapacity]; +} +/** + * Clears the hash table so that it has no more elements in it. + */ +public void clear() { + for (int i = keyTable.length; --i >= 0;) { + keyTable[i] = 0.0; + valueTable[i] = 0; + } + elementSize = 0; +} +/** Returns true if the collection contains an element for the key. + * + * @param key double the key that we are looking for + * @return boolean + */ +public boolean containsKey(double key) { + if (key == 0.0) { + for (int i = 0, max = elementSize; i < max; i++) { + if (keyTable[i] == 0.0) { + long value1 = Double.doubleToLongBits(key); + long value2 = Double.doubleToLongBits(keyTable[i]); + if (value1 == -9223372036854775808L && value2 == -9223372036854775808L) + return true; + if (value1 == 0 && value2 == 0) + return true; + } + } + } else { + for (int i = 0, max = elementSize; i < max; i++) { + if (keyTable[i] == key) { + return true; + } + } + } + return false; +} +/** Gets the object associated with the specified key in the + * hashtable. + * @param key double the specified key + * @return int the element for the key or -1 if the key is not + * defined in the hash table. + */ +public int get(double key) { + if (key == 0.0) { + for (int i = 0, max = elementSize; i < max; i++) { + if (keyTable[i] == 0.0) { + long value1 = Double.doubleToLongBits(key); + long value2 = Double.doubleToLongBits(keyTable[i]); + if (value1 == -9223372036854775808L && value2 == -9223372036854775808L) + return valueTable[i]; + if (value1 == 0 && value2 == 0) + return valueTable[i]; + } + } + } else { + for (int i = 0, max = elementSize; i < max; i++) { + if (keyTable[i] == key) { + return valueTable[i]; + } + } + } + return -1; +} +/** + * Puts the specified element into the hashtable, using the specified + * key. The element may be retrieved by doing a get() with the same key. + * + * @param key double the specified key in the hashtable + * @param value int the specified element + * @return int value + */ +public int put(double key, int value) { + if (elementSize == keyTable.length) { + // resize + System.arraycopy(keyTable, 0, (keyTable = new double[elementSize * 2]), 0, elementSize); + System.arraycopy(valueTable, 0, (valueTable = new int[elementSize * 2]), 0, elementSize); + } + keyTable[elementSize] = key; + valueTable[elementSize] = value; + elementSize++; + return value; +} +/** + * Converts to a rather lengthy String. + * + * @return String the ascii representation of the receiver + */ +public String toString() { + int max = elementSize; + StringBuffer buf = new StringBuffer(); + buf.append("{"); //$NON-NLS-1$ + for (int i = 0; i < max; ++i) { + if ((keyTable[i] != 0) || ((keyTable[i] == 0) &&(valueTable[i] != 0))) { + buf.append(keyTable[i]).append("->").append(valueTable[i]); //$NON-NLS-1$ + } + if (i < max) { + buf.append(", "); //$NON-NLS-1$ + } + } + buf.append("}"); //$NON-NLS-1$ + return buf.toString(); +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/codegen/ExceptionLabel.java b/src/java/org/eclipse/jdt/internal/compiler/codegen/ExceptionLabel.java new file mode 100644 index 0000000..31b2ee5 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/codegen/ExceptionLabel.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.codegen; + +import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; + +public class ExceptionLabel extends Label { + + public int start = POS_NOT_SET; + public int end = POS_NOT_SET; + public TypeBinding exceptionType; + + public ExceptionLabel(CodeStream codeStream, TypeBinding exceptionType) { + + super(codeStream); + this.exceptionType = exceptionType; + this.placeStart(); + } + + public boolean isStandardLabel(){ + + return false; + } + + public void place() { + + // register the handler inside the codeStream then normal place + codeStream.registerExceptionHandler(this); + super.place(); + } + + public void placeEnd() { + + this.end = codeStream.position; + } + + public void placeStart() { + + this.start = codeStream.position; + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/codegen/FieldNameAndTypeCache.java b/src/java/org/eclipse/jdt/internal/compiler/codegen/FieldNameAndTypeCache.java new file mode 100644 index 0000000..0982a06 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/codegen/FieldNameAndTypeCache.java @@ -0,0 +1,161 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.codegen; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; + +public class FieldNameAndTypeCache { + public FieldBinding keyTable[]; + public int valueTable[]; + int elementSize; + int threshold; +/** + * Constructs a new, empty hashtable. A default capacity is used. + * Note that the hashtable will automatically grow when it gets full. + */ +public FieldNameAndTypeCache() { + this(13); +} +/** + * Constructs a new, empty hashtable with the specified initial + * capacity. + * @param initialCapacity int + * the initial number of buckets + */ +public FieldNameAndTypeCache(int initialCapacity) { + this.elementSize = 0; + this.threshold = (int) (initialCapacity * 0.66f); + this.keyTable = new FieldBinding[initialCapacity]; + this.valueTable = new int[initialCapacity]; +} +/** + * Clears the hash table so that it has no more elements in it. + */ +public void clear() { + for (int i = keyTable.length; --i >= 0;) { + keyTable[i] = null; + valueTable[i] = 0; + } + elementSize = 0; +} +/** Returns true if the collection contains an element for the key. + * + * @param key char[] the key that we are looking for + * @return boolean + */ +public boolean containsKey(FieldBinding key) { + int index = hashCode(key); + while (keyTable[index] != null) { + if (equalsForNameAndType(keyTable[index], key)) + return true; + index = (index + 1) % keyTable.length; + } + return false; +} +/** + * Return true if the two field binding are consider like equals. + */ +public boolean equalsForNameAndType(FieldBinding field1, FieldBinding field2) { + return ((field1.type == field2.type) && CharOperation.equals(field1.name, field2.name)); +} +/** Gets the object associated with the specified key in the + * hashtable. + * @param key char[] the specified key + * @return int the element for the key or -1 if the key is not + * defined in the hash table. + */ +public int get(FieldBinding key) { + int index = hashCode(key); + while (keyTable[index] != null) { + if (equalsForNameAndType(keyTable[index], key)) + return valueTable[index]; + index = (index + 1) % keyTable.length; + } + return -1; +} +/** + * Return the hashcode for the key parameter + * + * @param key org.eclipse.jdt.internal.compiler.lookup.MethodBinding + * @return int + */ +public int hashCode(FieldBinding key) { + return ((CharOperation.hashCode(key.name) + key.type.hashCode()) & 0x7FFFFFFF) % keyTable.length; +} +/** + * Puts the specified element into the hashtable, using the specified + * key. The element may be retrieved by doing a get() with the same key. + * The key and the element cannot be null. + * + * @param key Object the specified key in the hashtable + * @param value int the specified element + * @return int the old value of the key, or -1 if it did not have one. + */ +public int put(FieldBinding key, int value) { + int index = hashCode(key); + while (keyTable[index] != null) { + if (equalsForNameAndType(keyTable[index], key)) + return valueTable[index] = value; + index = (index + 1) % keyTable.length; + } + keyTable[index] = key; + valueTable[index] = value; + + // assumes the threshold is never equal to the size of the table + if (++elementSize > threshold) + rehash(); + return value; +} +/** + * Rehashes the content of the table into a bigger table. + * This method is called automatically when the hashtable's + * size exceeds the threshold. + */ +private void rehash() { + FieldNameAndTypeCache newHashtable = new FieldNameAndTypeCache(keyTable.length * 2); + for (int i = keyTable.length; --i >= 0;) + if (keyTable[i] != null) + newHashtable.put(keyTable[i], valueTable[i]); + + this.keyTable = newHashtable.keyTable; + this.valueTable = newHashtable.valueTable; + this.threshold = newHashtable.threshold; +} +/** + * Returns the number of elements contained in the hashtable. + * + * @return int The size of the table + */ +public int size() { + return elementSize; +} +/** + * Converts to a rather lengthy String. + * + * @return String the ascii representation of the receiver + */ +public String toString() { + int max = size(); + StringBuffer buf = new StringBuffer(); + buf.append("{"); //$NON-NLS-1$ + for (int i = 0; i < max; ++i) { + if (keyTable[i] != null) { + buf.append(keyTable[i]).append("->").append(valueTable[i]); //$NON-NLS-1$ + } + if (i < max) { + buf.append(", "); //$NON-NLS-1$ + } + } + buf.append("}"); //$NON-NLS-1$ + return buf.toString(); +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/codegen/FloatCache.java b/src/java/org/eclipse/jdt/internal/compiler/codegen/FloatCache.java new file mode 100644 index 0000000..3bbe945 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/codegen/FloatCache.java @@ -0,0 +1,138 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.codegen; + +public class FloatCache { + private float keyTable[]; + private int valueTable[]; + private int elementSize; +/** + * Constructs a new, empty hashtable. A default capacity and + * load factor is used. Note that the hashtable will automatically + * grow when it gets full. + */ +public FloatCache() { + this(13); +} +/** + * Constructs a new, empty hashtable with the specified initial + * capacity. + * @param initialCapacity int + * the initial number of buckets + */ +public FloatCache(int initialCapacity) { + elementSize = 0; + keyTable = new float[initialCapacity]; + valueTable = new int[initialCapacity]; +} +/** + * Clears the hash table so that it has no more elements in it. + */ +public void clear() { + for (int i = keyTable.length; --i >= 0;) { + keyTable[i] = 0.0f; + valueTable[i] = 0; + } + elementSize = 0; +} +/** Returns true if the collection contains an element for the key. + * + * @param key float the key that we are looking for + * @return boolean + */ +public boolean containsKey(float key) { + if (key == 0.0f) { + for (int i = 0, max = elementSize; i < max; i++) { + if (keyTable[i] == 0.0f) { + int value1 = Float.floatToIntBits(key); + int value2 = Float.floatToIntBits(keyTable[i]); + if (value1 == -2147483648 && value2 == -2147483648) + return true; + if (value1 == 0 && value2 == 0) + return true; + } + } + } else { + for (int i = 0, max = elementSize; i < max; i++) { + if (keyTable[i] == key) { + return true; + } + } + } + return false; +} +/** Gets the object associated with the specified key in the + * hashtable. + * @param key float the specified key + * @return int the element for the key or -1 if the key is not + * defined in the hash table. + */ +public int get(float key) { + if (key == 0.0f) { + for (int i = 0, max = elementSize; i < max; i++) { + if (keyTable[i] == 0.0f) { + int value1 = Float.floatToIntBits(key); + int value2 = Float.floatToIntBits(keyTable[i]); + if (value1 == -2147483648 && value2 == -2147483648) + return valueTable[i]; + if (value1 == 0 && value2 == 0) + return valueTable[i]; + } + } + } else { + for (int i = 0, max = elementSize; i < max; i++) { + if (keyTable[i] == key) { + return valueTable[i]; + } + } + } + return -1; +} +/** + * Puts the specified element into the hashtable, using the specified + * key. The element may be retrieved by doing a get() with the same key. + * + * @param key float the specified key in the hashtable + * @param value int the specified element + * @return int value + */ +public int put(float key, int value) { + if (elementSize == keyTable.length) { + // resize + System.arraycopy(keyTable, 0, (keyTable = new float[elementSize * 2]), 0, elementSize); + System.arraycopy(valueTable, 0, (valueTable = new int[elementSize * 2]), 0, elementSize); + } + keyTable[elementSize] = key; + valueTable[elementSize] = value; + elementSize++; + return value; +} +/** + * Converts to a rather lengthy String. + * + * @return String the ascii representation of the receiver + */ +public String toString() { + int max = elementSize; + StringBuffer buf = new StringBuffer(); + buf.append("{"); //$NON-NLS-1$ + for (int i = 0; i < max; ++i) { + if ((keyTable[i] != 0) || ((keyTable[i] == 0) && (valueTable[i] != 0))) { + buf.append(keyTable[i]).append("->").append(valueTable[i]); //$NON-NLS-1$ + } + if (i < max) { + buf.append(", "); //$NON-NLS-1$ + } + } + buf.append("}"); //$NON-NLS-1$ + return buf.toString(); +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/codegen/IntegerCache.java b/src/java/org/eclipse/jdt/internal/compiler/codegen/IntegerCache.java new file mode 100644 index 0000000..91b36a6 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/codegen/IntegerCache.java @@ -0,0 +1,155 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.codegen; + +public class IntegerCache { + public int keyTable[]; + public int valueTable[]; + int elementSize; + int threshold; +/** + * Constructs a new, empty hashtable. A default capacity and + * load factor is used. Note that the hashtable will automatically + * grow when it gets full. + */ +public IntegerCache() { + this(13); +} +/** + * Constructs a new, empty hashtable with the specified initial + * capacity. + * @param initialCapacity int + * the initial number of buckets + */ +public IntegerCache(int initialCapacity) { + elementSize = 0; + threshold = (int) (initialCapacity * 0.66); + keyTable = new int[initialCapacity]; + valueTable = new int[initialCapacity]; +} +/** + * Clears the hash table so that it has no more elements in it. + */ +public void clear() { + for (int i = keyTable.length; --i >= 0;) { + keyTable[i] = 0; + valueTable[i] = 0; + } + elementSize = 0; +} +/** Returns true if the collection contains an element for the key. + * + * @param key double the key that we are looking for + * @return boolean + */ +public boolean containsKey(int key) { + int index = hash(key); + while ((keyTable[index] != 0) || ((keyTable[index] == 0) &&(valueTable[index] != 0))) { + if (keyTable[index] == key) + return true; + index = (index + 1) % keyTable.length; + } + return false; +} +/** Gets the object associated with the specified key in the + * hashtable. + * @param key double the specified key + * @return int the element for the key or -1 if the key is not + * defined in the hash table. + */ +public int get(int key) { + int index = hash(key); + while ((keyTable[index] != 0) || ((keyTable[index] == 0) &&(valueTable[index] != 0))) { + if (keyTable[index] == key) + return valueTable[index]; + index = (index + 1) % keyTable.length; + } + return -1; +} +/** + * Return a hashcode for the value of the key parameter. + * @param key int + * @return int the hash code corresponding to the key value + */ +public int hash(int key) { + return (key & 0x7FFFFFFF) % keyTable.length; +} +/** + * Puts the specified element into the hashtable, using the specified + * key. The element may be retrieved by doing a get() with the same key. + * + * @param key int the specified key in the hashtable + * @param value int the specified element + * @return int value + */ +public int put(int key, int value) { + int index = hash(key); + while ((keyTable[index] != 0) || ((keyTable[index] == 0) && (valueTable[index] != 0))) { + if (keyTable[index] == key) + return valueTable[index] = value; + index = (index + 1) % keyTable.length; + } + keyTable[index] = key; + valueTable[index] = value; + + // assumes the threshold is never equal to the size of the table + if (++elementSize > threshold) { + rehash(); + } + return value; +} +/** + * Rehashes the content of the table into a bigger table. + * This method is called automatically when the hashtable's + * size exceeds the threshold. + */ +private void rehash() { + IntegerCache newHashtable = new IntegerCache(keyTable.length * 2); + for (int i = keyTable.length; --i >= 0;) { + int key = keyTable[i]; + int value = valueTable[i]; + if ((key != 0) || ((key == 0) && (value != 0))) { + newHashtable.put(key, value); + } + } + this.keyTable = newHashtable.keyTable; + this.valueTable = newHashtable.valueTable; + this.threshold = newHashtable.threshold; +} +/** + * Returns the number of elements contained in the hashtable. + * + * @return int The size of the table + */ +public int size() { + return elementSize; +} +/** + * Converts to a rather lengthy String. + * + * @return String the ascii representation of the receiver + */ +public String toString() { + int max = size(); + StringBuffer buf = new StringBuffer(); + buf.append("{"); //$NON-NLS-1$ + for (int i = 0; i < max; ++i) { + if ((keyTable[i] != 0) || ((keyTable[i] == 0) && (valueTable[i] != 0))) { + buf.append(keyTable[i]).append("->").append(valueTable[i]); //$NON-NLS-1$ + } + if (i < max) { + buf.append(", "); //$NON-NLS-1$ + } + } + buf.append("}"); //$NON-NLS-1$ + return buf.toString(); +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/codegen/Label.java b/src/java/org/eclipse/jdt/internal/compiler/codegen/Label.java new file mode 100644 index 0000000..8c29bce --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/codegen/Label.java @@ -0,0 +1,262 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.codegen; + +import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; +import org.eclipse.jdt.internal.compiler.problem.AbortMethod; + +/** + * This type is a port of smalltalks JavaLabel + */ +public class Label { + public CodeStream codeStream; + final static int POS_NOT_SET = -1; + public int position = POS_NOT_SET; // position=POS_NOT_SET Then it's pos is not set. + public int[] forwardReferences = new int[10]; // Add an overflow check here. + public int forwardReferenceCount = 0; + private boolean isWide = false; + +public Label() { + // for creating labels ahead of code generation +} +/** + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + */ +public Label(CodeStream codeStream) { + this.codeStream = codeStream; +} +/** + * Add a forward refrence for the array. + */ +void addForwardReference(int iPos) { + int length; + if (forwardReferenceCount >= (length = forwardReferences.length)) + System.arraycopy(forwardReferences, 0, (forwardReferences = new int[2*length]), 0, length); + forwardReferences[forwardReferenceCount++] = iPos; +} +/** + * Add a forward refrence for the array. + */ +public void appendForwardReferencesFrom(Label otherLabel) { + int otherCount = otherLabel.forwardReferenceCount; + if (otherCount == 0) return; + int length = forwardReferences.length; + int neededSpace = otherCount + forwardReferenceCount; + if (neededSpace >= length){ + System.arraycopy(forwardReferences, 0, (forwardReferences = new int[neededSpace]), 0, forwardReferenceCount); + } + // append other forward references at the end, so they will get updated as well + System.arraycopy(otherLabel.forwardReferences, 0, forwardReferences, forwardReferenceCount, otherCount); + forwardReferenceCount = neededSpace; +} +/* +* Put down a reference to the array at the location in the codestream. +*/ +void branch() { + if (position == POS_NOT_SET) { + addForwardReference(codeStream.position); + // Leave two bytes free to generate the jump afterwards + codeStream.position += 2; + codeStream.classFileOffset += 2; + } else { + /* + * Position is set. Write it if it is not a wide branch. + */ + int offset = position - codeStream.position + 1; + if (Math.abs(offset) > 0x7FFF && !this.codeStream.wideMode) { + throw new AbortMethod(CodeStream.RESTART_IN_WIDE_MODE, null); + } + codeStream.writeSignedShort(offset); + } +} +/* +* No support for wide branches yet +*/ +void branchWide() { + if (position == POS_NOT_SET) { + addForwardReference(codeStream.position); + // Leave 4 bytes free to generate the jump offset afterwards + isWide = true; + codeStream.position += 4; + codeStream.classFileOffset += 4; + } else { //Position is set. Write it! + codeStream.writeSignedWord(position - codeStream.position + 1); + } +} +/** + * @return boolean + */ +public boolean hasForwardReferences() { + return forwardReferenceCount != 0; +} +/* + * Some placed labels might be branching to a goto bytecode which we can optimize better. + */ +public void inlineForwardReferencesFromLabelsTargeting(int gotoLocation) { + +/* + Code required to optimized unreachable gotos. + public boolean isBranchTarget(int location) { + Label[] labels = codeStream.labels; + for (int i = codeStream.countLabels - 1; i >= 0; i--){ + Label label = labels[i]; + if ((label.position == location) && label.isStandardLabel()){ + return true; + } + } + return false; + } + */ + + Label[] labels = codeStream.labels; + for (int i = codeStream.countLabels - 1; i >= 0; i--){ + Label label = labels[i]; + if ((label.position == gotoLocation) && label.isStandardLabel()){ + this.appendForwardReferencesFrom(label); + /* + Code required to optimized unreachable gotos. + label.position = POS_NOT_SET; + */ + } else { + break; // same target labels should be contiguous + } + } +} +public void initialize(CodeStream stream) { + this.codeStream = stream; + this.position = POS_NOT_SET; + this.forwardReferenceCount = 0; +} +public boolean isStandardLabel(){ + return true; +} +/* +* Place the label. If we have forward references resolve them. +*/ +public void place() { // Currently lacking wide support. + if (CodeStream.DEBUG) System.out.println("\t\t\t\t= 0) && (codeStream.pcToSourceMap[index][1] == oldPosition)) { + codeStream.pcToSourceMap[index--][1] = position; + } + */ + // Beginning of new code + int index = codeStream.pcToSourceMapSize - 2; + if (codeStream.lastEntryPC == oldPosition) { + codeStream.lastEntryPC = position; + } + if ((index >= 0) && (codeStream.pcToSourceMap[index] == position)) { + codeStream.pcToSourceMapSize-=2; + } + // end of new code + if (codeStream.generateLocalVariableTableAttributes) { + LocalVariableBinding locals[] = codeStream.locals; + for (int i = 0, max = locals.length; i < max; i++) { + LocalVariableBinding local = locals[i]; + if ((local != null) && (local.initializationCount > 0)) { + if (local.initializationPCs[((local.initializationCount - 1) << 1) + 1] == oldPosition) { + // we want to prevent interval of size 0 to have a negative size. + // see PR 1GIRQLA: ITPJCORE:ALL - ClassFormatError for local variable attribute + local.initializationPCs[((local.initializationCount - 1) << 1) + 1] = position; + } + if (local.initializationPCs[(local.initializationCount - 1) << 1] == oldPosition) { + local.initializationPCs[(local.initializationCount - 1) << 1] = position; + } + } + } + } + } + } + for (int i = 0; i < forwardReferenceCount; i++) { + int offset = position - forwardReferences[i] + 1; + if (Math.abs(offset) > 0x7FFF && !this.codeStream.wideMode) { + throw new AbortMethod(CodeStream.RESTART_IN_WIDE_MODE, null); + } + if (this.codeStream.wideMode) { + if (this.isWide) { + codeStream.writeSignedWord(forwardReferences[i], offset); + } else { + codeStream.writeSignedShort(forwardReferences[i], offset); + } + } else { + codeStream.writeSignedShort(forwardReferences[i], offset); + } + } + // For all labels placed at that position we check if we need to rewrite the jump + // offset. It is the case each time a label had a forward reference to the current position. + // Like we change the current position, we have to change the jump offset. See 1F4IRD9 for more details. + if (isOptimizedBranch) { + for (int i = 0; i < codeStream.countLabels; i++) { + Label label = codeStream.labels[i]; + if (oldPosition == label.position) { + label.position = position; + if (label instanceof CaseLabel) { + int offset = position - ((CaseLabel) label).instructionPosition; + for (int j = 0; j < label.forwardReferenceCount; j++) { + int forwardPosition = label.forwardReferences[j]; + codeStream.writeSignedWord(forwardPosition, offset); + } + } else { + for (int j = 0; j < label.forwardReferenceCount; j++) { + int forwardPosition = label.forwardReferences[j]; + int offset = position - forwardPosition + 1; + if (Math.abs(offset) > 0x7FFF && !this.codeStream.wideMode) { + throw new AbortMethod(CodeStream.RESTART_IN_WIDE_MODE, null); + } + if (this.codeStream.wideMode) { + if (this.isWide) { + codeStream.writeSignedWord(forwardPosition, offset); + } else { + codeStream.writeSignedShort(forwardPosition, offset); + } + } else { + codeStream.writeSignedShort(forwardPosition, offset); + } + } + } + } + } + } + } +} +/** + * Print out the receiver + */ +public String toString() { + String basic = getClass().getName(); + basic = basic.substring(basic.lastIndexOf('.')+1); + StringBuffer buffer = new StringBuffer(basic); + buffer.append('@').append(Integer.toHexString(hashCode())); + buffer.append("(position=").append(position); //$NON-NLS-1$ + buffer.append(", forwards = ["); //$NON-NLS-1$ + for (int i = 0; i < forwardReferenceCount - 1; i++) + buffer.append(forwardReferences[i] + ", "); //$NON-NLS-1$ + if (forwardReferenceCount >= 1) + buffer.append(forwardReferences[forwardReferenceCount-1]); + buffer.append("] )"); //$NON-NLS-1$ + return buffer.toString(); +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/codegen/LongCache.java b/src/java/org/eclipse/jdt/internal/compiler/codegen/LongCache.java new file mode 100644 index 0000000..cfb5f08 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/codegen/LongCache.java @@ -0,0 +1,155 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.codegen; + +public class LongCache { + public long keyTable[]; + public int valueTable[]; + int elementSize; + int threshold; +/** + * Constructs a new, empty hashtable. A default capacity and + * load factor is used. Note that the hashtable will automatically + * grow when it gets full. + */ +public LongCache() { + this(13); +} +/** + * Constructs a new, empty hashtable with the specified initial + * capacity. + * @param initialCapacity int + * the initial number of buckets + */ +public LongCache(int initialCapacity) { + elementSize = 0; + threshold = (int) (initialCapacity * 0.66); + keyTable = new long[initialCapacity]; + valueTable = new int[initialCapacity]; +} +/** + * Clears the hash table so that it has no more elements in it. + */ +public void clear() { + for (int i = keyTable.length; --i >= 0;) { + keyTable[i] = 0; + valueTable[i] = 0; + } + elementSize = 0; +} +/** Returns true if the collection contains an element for the key. + * + * @param key long the key that we are looking for + * @return boolean + */ +public boolean containsKey(long key) { + int index = hash(key); + while ((keyTable[index] != 0) || ((keyTable[index] == 0) &&(valueTable[index] != 0))) { + if (keyTable[index] == key) + return true; + index = (index + 1) % keyTable.length; + } + return false; +} +/** Gets the object associated with the specified key in the + * hashtable. + * @param key long the specified key + * @return int the element for the key or -1 if the key is not + * defined in the hash table. + */ +public int get(long key) { + int index = hash(key); + while ((keyTable[index] != 0) || ((keyTable[index] == 0) &&(valueTable[index] != 0))) { + if (keyTable[index] == key) + return valueTable[index]; + index = (index + 1) % keyTable.length; + } + return -1; +} +/** + * Return a hashcode for the value of the key parameter. + * @param key long + * @return int the hash code corresponding to the key value + */ +public int hash(long key) { + return ((int) key & 0x7FFFFFFF) % keyTable.length; +} +/** + * Puts the specified element into the hashtable, using the specified + * key. The element may be retrieved by doing a get() with the same key. + * + * @param key long the specified key in the hashtable + * @param value int the specified element + * @return int value + */ +public int put(long key, int value) { + int index = hash(key); + while ((keyTable[index] != 0) || ((keyTable[index] == 0) && (valueTable[index] != 0))) { + if (keyTable[index] == key) + return valueTable[index] = value; + index = (index + 1) % keyTable.length; + } + keyTable[index] = key; + valueTable[index] = value; + + // assumes the threshold is never equal to the size of the table + if (++elementSize > threshold) { + rehash(); + } + return value; +} +/** + * Rehashes the content of the table into a bigger table. + * This method is called automatically when the hashtable's + * size exceeds the threshold. + */ +private void rehash() { + LongCache newHashtable = new LongCache(keyTable.length * 2); + for (int i = keyTable.length; --i >= 0;) { + long key = keyTable[i]; + int value = valueTable[i]; + if ((key != 0) || ((key == 0) && (value != 0))) { + newHashtable.put(key, value); + } + } + this.keyTable = newHashtable.keyTable; + this.valueTable = newHashtable.valueTable; + this.threshold = newHashtable.threshold; +} +/** + * Returns the number of elements contained in the hashtable. + * + * @return int The size of the table + */ +public int size() { + return elementSize; +} +/** + * Converts to a rather lengthy String. + * + * @return String the ascii representation of the receiver + */ +public String toString() { + int max = size(); + StringBuffer buf = new StringBuffer(); + buf.append("{"); //$NON-NLS-1$ + for (int i = 0; i < max; ++i) { + if ((keyTable[i] != 0) || ((keyTable[i] == 0) && (valueTable[i] != 0))) { + buf.append(keyTable[i]).append("->").append(valueTable[i]); //$NON-NLS-1$ + } + if (i < max) { + buf.append(", "); //$NON-NLS-1$ + } + } + buf.append("}"); //$NON-NLS-1$ + return buf.toString(); +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/codegen/MethodNameAndTypeCache.java b/src/java/org/eclipse/jdt/internal/compiler/codegen/MethodNameAndTypeCache.java new file mode 100644 index 0000000..2ab3da3 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/codegen/MethodNameAndTypeCache.java @@ -0,0 +1,162 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.codegen; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; + +public class MethodNameAndTypeCache { + public MethodBinding keyTable[]; + public int valueTable[]; + int elementSize; + int threshold; +/** + * Constructs a new, empty hashtable. A default capacity is used. + * Note that the hashtable will automatically grow when it gets full. + */ +public MethodNameAndTypeCache() { + this(13); +} +/** + * Constructs a new, empty hashtable with the specified initial + * capacity. + * @param initialCapacity int + * the initial number of buckets + */ +public MethodNameAndTypeCache(int initialCapacity) { + this.elementSize = 0; + this.threshold = (int) (initialCapacity * 0.66f); + this.keyTable = new MethodBinding[initialCapacity]; + this.valueTable = new int[initialCapacity]; +} +/** + * Clears the hash table so that it has no more elements in it. + */ +public void clear() { + for (int i = keyTable.length; --i >= 0;) { + keyTable[i] = null; + valueTable[i] = 0; + } + elementSize = 0; +} +/** Returns true if the collection contains an element for the key. + * + * @param key char[] the key that we are looking for + * @return boolean + */ +public boolean containsKey(MethodBinding key) { + int index = hashCode(key); + while (keyTable[index] != null) { + if (equalsForNameAndType(keyTable[index], key)) + return true; + index = (index + 1) % keyTable.length; + } + return false; +} +/** + * Returns true if the two methodBinding are consider to be equal for the name and type + * purpose + */ +public boolean equalsForNameAndType(MethodBinding method1, MethodBinding method2) { + return CharOperation.equals(method1.selector, method2.selector) && CharOperation.equals(method1.signature(), method2.signature()); +} +/** Gets the object associated with the specified key in the + * hashtable. + * @param key char[] the specified key + * @return int the element for the key or -1 if the key is not + * defined in the hash table. + */ +public int get(MethodBinding key) { + int index = hashCode(key); + while (keyTable[index] != null) { + if (equalsForNameAndType(keyTable[index], key)) + return valueTable[index]; + index = (index + 1) % keyTable.length; + } + return -1; +} +/** + * Return the hashcode for the key parameter + * + * @param key org.eclipse.jdt.internal.compiler.lookup.MethodBinding + * @return int + */ +public int hashCode(MethodBinding key) { + return CharOperation.hashCode(key.selector) % keyTable.length; +} +/** + * Puts the specified element into the hashtable, using the specified + * key. The element may be retrieved by doing a get() with the same key. + * The key and the element cannot be null. + * + * @param key Object the specified key in the hashtable + * @param value int the specified element + * @return int the old value of the key, or -1 if it did not have one. + */ +public int put(MethodBinding key, int value) { + int index = hashCode(key); + while (keyTable[index] != null) { + if (equalsForNameAndType(keyTable[index], key)) + return valueTable[index] = value; + index = (index + 1) % keyTable.length; + } + keyTable[index] = key; + valueTable[index] = value; + + // assumes the threshold is never equal to the size of the table + if (++elementSize > threshold) + rehash(); + return value; +} +/** + * Rehashes the content of the table into a bigger table. + * This method is called automatically when the hashtable's + * size exceeds the threshold. + */ +private void rehash() { + MethodNameAndTypeCache newHashtable = new MethodNameAndTypeCache(keyTable.length * 2); + for (int i = keyTable.length; --i >= 0;) + if (keyTable[i] != null) + newHashtable.put(keyTable[i], valueTable[i]); + + this.keyTable = newHashtable.keyTable; + this.valueTable = newHashtable.valueTable; + this.threshold = newHashtable.threshold; +} +/** + * Returns the number of elements contained in the hashtable. + * + * @return int The size of the table + */ +public int size() { + return elementSize; +} +/** + * Converts to a rather lengthy String. + * + * @return String the ascii representation of the receiver + */ +public String toString() { + int max = size(); + StringBuffer buf = new StringBuffer(); + buf.append("{"); //$NON-NLS-1$ + for (int i = 0; i < max; ++i) { + if (keyTable[i] != null) { + buf.append(keyTable[i]).append("->").append(valueTable[i]); //$NON-NLS-1$ + } + if (i < max) { + buf.append(", "); //$NON-NLS-1$ + } + } + buf.append("}"); //$NON-NLS-1$ + return buf.toString(); +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/codegen/ObjectCache.java b/src/java/org/eclipse/jdt/internal/compiler/codegen/ObjectCache.java new file mode 100644 index 0000000..a1ff0eb --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/codegen/ObjectCache.java @@ -0,0 +1,152 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.codegen; + +public class ObjectCache { + public Object keyTable[]; + public int valueTable[]; + int elementSize; + int threshold; +/** + * Constructs a new, empty hashtable. A default capacity is used. + * Note that the hashtable will automatically grow when it gets full. + */ +public ObjectCache() { + this(13); +} +/** + * Constructs a new, empty hashtable with the specified initial + * capacity. + * @param initialCapacity int + * the initial number of buckets + */ +public ObjectCache(int initialCapacity) { + this.elementSize = 0; + this.threshold = (int) (initialCapacity * 0.66f); + this.keyTable = new Object[initialCapacity]; + this.valueTable = new int[initialCapacity]; +} +/** + * Clears the hash table so that it has no more elements in it. + */ +public void clear() { + for (int i = keyTable.length; --i >= 0;) { + keyTable[i] = null; + valueTable[i] = 0; + } + elementSize = 0; +} +/** Returns true if the collection contains an element for the key. + * + * @param key char[] the key that we are looking for + * @return boolean + */ +public boolean containsKey(Object key) { + int index = hashCode(key); + while (keyTable[index] != null) { + if (keyTable[index] == key) + return true; + index = (index + 1) % keyTable.length; + } + return false; +} +/** Gets the object associated with the specified key in the + * hashtable. + * @param key char[] the specified key + * @return int the element for the key or -1 if the key is not + * defined in the hash table. + */ +public int get(Object key) { + int index = hashCode(key); + while (keyTable[index] != null) { + if (keyTable[index] == key) + return valueTable[index]; + index = (index + 1) % keyTable.length; + } + return -1; +} +/** + * Return the hashcode for the key parameter + * + * @param key org.eclipse.jdt.internal.compiler.lookup.MethodBinding + * @return int + */ +public int hashCode(Object key) { + return (key.hashCode() & 0x7FFFFFFF) % keyTable.length; +} +/** + * Puts the specified element into the hashtable, using the specified + * key. The element may be retrieved by doing a get() with the same key. + * The key and the element cannot be null. + * + * @param key Object the specified key in the hashtable + * @param value int the specified element + * @return int the old value of the key, or -1 if it did not have one. + */ +public int put(Object key, int value) { + int index = hashCode(key); + while (keyTable[index] != null) { + if (keyTable[index] == key) + return valueTable[index] = value; + index = (index + 1) % keyTable.length; + } + keyTable[index] = key; + valueTable[index] = value; + + // assumes the threshold is never equal to the size of the table + if (++elementSize > threshold) + rehash(); + return value; +} +/** + * Rehashes the content of the table into a bigger table. + * This method is called automatically when the hashtable's + * size exceeds the threshold. + */ +private void rehash() { + ObjectCache newHashtable = new ObjectCache(keyTable.length * 2); + for (int i = keyTable.length; --i >= 0;) + if (keyTable[i] != null) + newHashtable.put(keyTable[i], valueTable[i]); + + this.keyTable = newHashtable.keyTable; + this.valueTable = newHashtable.valueTable; + this.threshold = newHashtable.threshold; +} +/** + * Returns the number of elements contained in the hashtable. + * + * @return int The size of the table + */ +public int size() { + return elementSize; +} +/** + * Converts to a rather lengthy String. + * + * @return String the ascii representation of the receiver + */ +public String toString() { + int max = size(); + StringBuffer buf = new StringBuffer(); + buf.append("{"); //$NON-NLS-1$ + for (int i = 0; i < max; ++i) { + if (keyTable[i] != null) { + buf.append(keyTable[i]).append("->").append(valueTable[i]); //$NON-NLS-1$ + } + if (i < max) { + buf.append(", "); //$NON-NLS-1$ + } + } + buf.append("}"); //$NON-NLS-1$ + return buf.toString(); +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/codegen/Opcodes.java b/src/java/org/eclipse/jdt/internal/compiler/codegen/Opcodes.java new file mode 100644 index 0000000..8fc2355 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/codegen/Opcodes.java @@ -0,0 +1,216 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.codegen; + +public interface Opcodes { + + public static final byte OPC_nop = 0; + public static final byte OPC_aconst_null = 1; + public static final byte OPC_iconst_m1 = 2; + public static final byte OPC_iconst_0 = 3; + public static final byte OPC_iconst_1 = 4; + public static final byte OPC_iconst_2 = 5; + public static final byte OPC_iconst_3 = 6; + public static final byte OPC_iconst_4 = 7; + public static final byte OPC_iconst_5 = 8; + public static final byte OPC_lconst_0 = 9; + public static final byte OPC_lconst_1 = 10; + public static final byte OPC_fconst_0 = 11; + public static final byte OPC_fconst_1 = 12; + public static final byte OPC_fconst_2 = 13; + public static final byte OPC_dconst_0 = 14; + public static final byte OPC_dconst_1 = 15; + public static final byte OPC_bipush = 16; + public static final byte OPC_sipush = 17; + public static final byte OPC_ldc = 18; + public static final byte OPC_ldc_w = 19; + public static final byte OPC_ldc2_w = 20; + public static final byte OPC_iload = 21; + public static final byte OPC_lload = 22; + public static final byte OPC_fload = 23; + public static final byte OPC_dload = 24; + public static final byte OPC_aload = 25; + public static final byte OPC_iload_0 = 26; + public static final byte OPC_iload_1 = 27; + public static final byte OPC_iload_2 = 28; + public static final byte OPC_iload_3 = 29; + public static final byte OPC_lload_0 = 30; + public static final byte OPC_lload_1 = 31; + public static final byte OPC_lload_2 = 32; + public static final byte OPC_lload_3 = 33; + public static final byte OPC_fload_0 = 34; + public static final byte OPC_fload_1 = 35; + public static final byte OPC_fload_2 = 36; + public static final byte OPC_fload_3 = 37; + public static final byte OPC_dload_0 = 38; + public static final byte OPC_dload_1 = 39; + public static final byte OPC_dload_2 = 40; + public static final byte OPC_dload_3 = 41; + public static final byte OPC_aload_0 = 42; + public static final byte OPC_aload_1 = 43; + public static final byte OPC_aload_2 = 44; + public static final byte OPC_aload_3 = 45; + public static final byte OPC_iaload = 46; + public static final byte OPC_laload = 47; + public static final byte OPC_faload = 48; + public static final byte OPC_daload = 49; + public static final byte OPC_aaload = 50; + public static final byte OPC_baload = 51; + public static final byte OPC_caload = 52; + public static final byte OPC_saload = 53; + public static final byte OPC_istore = 54; + public static final byte OPC_lstore = 55; + public static final byte OPC_fstore = 56; + public static final byte OPC_dstore = 57; + public static final byte OPC_astore = 58; + public static final byte OPC_istore_0 = 59; + public static final byte OPC_istore_1 = 60; + public static final byte OPC_istore_2 = 61; + public static final byte OPC_istore_3 = 62; + public static final byte OPC_lstore_0 = 63; + public static final byte OPC_lstore_1 = 64; + public static final byte OPC_lstore_2 = 65; + public static final byte OPC_lstore_3 = 66; + public static final byte OPC_fstore_0 = 67; + public static final byte OPC_fstore_1 = 68; + public static final byte OPC_fstore_2 = 69; + public static final byte OPC_fstore_3 = 70; + public static final byte OPC_dstore_0 = 71; + public static final byte OPC_dstore_1 = 72; + public static final byte OPC_dstore_2 = 73; + public static final byte OPC_dstore_3 = 74; + public static final byte OPC_astore_0 = 75; + public static final byte OPC_astore_1 = 76; + public static final byte OPC_astore_2 = 77; + public static final byte OPC_astore_3 = 78; + public static final byte OPC_iastore = 79; + public static final byte OPC_lastore = 80; + public static final byte OPC_fastore = 81; + public static final byte OPC_dastore = 82; + public static final byte OPC_aastore = 83; + public static final byte OPC_bastore = 84; + public static final byte OPC_castore = 85; + public static final byte OPC_sastore = 86; + public static final byte OPC_pop = 87; + public static final byte OPC_pop2 = 88; + public static final byte OPC_dup = 89; + public static final byte OPC_dup_x1 = 90; + public static final byte OPC_dup_x2 = 91; + public static final byte OPC_dup2 = 92; + public static final byte OPC_dup2_x1 = 93; + public static final byte OPC_dup2_x2 = 94; + public static final byte OPC_swap = 95; + public static final byte OPC_iadd = 96; + public static final byte OPC_ladd = 97; + public static final byte OPC_fadd = 98; + public static final byte OPC_dadd = 99; + public static final byte OPC_isub = 100; + public static final byte OPC_lsub = 101; + public static final byte OPC_fsub = 102; + public static final byte OPC_dsub = 103; + public static final byte OPC_imul = 104; + public static final byte OPC_lmul = 105; + public static final byte OPC_fmul = 106; + public static final byte OPC_dmul = 107; + public static final byte OPC_idiv = 108; + public static final byte OPC_ldiv = 109; + public static final byte OPC_fdiv = 110; + public static final byte OPC_ddiv = 111; + public static final byte OPC_irem = 112; + public static final byte OPC_lrem = 113; + public static final byte OPC_frem = 114; + public static final byte OPC_drem = 115; + public static final byte OPC_ineg = 116; + public static final byte OPC_lneg = 117; + public static final byte OPC_fneg = 118; + public static final byte OPC_dneg = 119; + public static final byte OPC_ishl = 120; + public static final byte OPC_lshl = 121; + public static final byte OPC_ishr = 122; + public static final byte OPC_lshr = 123; + public static final byte OPC_iushr = 124; + public static final byte OPC_lushr = 125; + public static final byte OPC_iand = 126; + public static final byte OPC_land = 127; + public static final byte OPC_ior = (byte) 128; + public static final byte OPC_lor = (byte) 129; + public static final byte OPC_ixor = (byte) 130; + public static final byte OPC_lxor = (byte) 131; + public static final byte OPC_iinc = (byte) 132; + public static final byte OPC_i2l = (byte) 133; + public static final byte OPC_i2f = (byte) 134; + public static final byte OPC_i2d = (byte) 135; + public static final byte OPC_l2i = (byte) 136; + public static final byte OPC_l2f = (byte) 137; + public static final byte OPC_l2d = (byte) 138; + public static final byte OPC_f2i = (byte) 139; + public static final byte OPC_f2l = (byte) 140; + public static final byte OPC_f2d = (byte) 141; + public static final byte OPC_d2i = (byte) 142; + public static final byte OPC_d2l = (byte) 143; + public static final byte OPC_d2f = (byte) 144; + public static final byte OPC_i2b = (byte) 145; + public static final byte OPC_i2c = (byte) 146; + public static final byte OPC_i2s = (byte) 147; + public static final byte OPC_lcmp = (byte) 148; + public static final byte OPC_fcmpl = (byte) 149; + public static final byte OPC_fcmpg = (byte) 150; + public static final byte OPC_dcmpl = (byte) 151; + public static final byte OPC_dcmpg = (byte) 152; + public static final byte OPC_ifeq = (byte) 153; + public static final byte OPC_ifne = (byte) 154; + public static final byte OPC_iflt = (byte) 155; + public static final byte OPC_ifge = (byte) 156; + public static final byte OPC_ifgt = (byte) 157; + public static final byte OPC_ifle = (byte) 158; + public static final byte OPC_if_icmpeq = (byte) 159; + public static final byte OPC_if_icmpne = (byte) 160; + public static final byte OPC_if_icmplt = (byte) 161; + public static final byte OPC_if_icmpge = (byte) 162; + public static final byte OPC_if_icmpgt = (byte) 163; + public static final byte OPC_if_icmple = (byte) 164; + public static final byte OPC_if_acmpeq = (byte) 165; + public static final byte OPC_if_acmpne = (byte) 166; + public static final byte OPC_goto = (byte) 167; + public static final byte OPC_jsr = (byte) 168; + public static final byte OPC_ret = (byte) 169; + public static final byte OPC_tableswitch = (byte) 170; + public static final byte OPC_lookupswitch = (byte) 171; + public static final byte OPC_ireturn = (byte) 172; + public static final byte OPC_lreturn = (byte) 173; + public static final byte OPC_freturn = (byte) 174; + public static final byte OPC_dreturn = (byte) 175; + public static final byte OPC_areturn = (byte) 176; + public static final byte OPC_return = (byte) 177; + public static final byte OPC_getstatic = (byte) 178; + public static final byte OPC_putstatic = (byte) 179; + public static final byte OPC_getfield = (byte) 180; + public static final byte OPC_putfield = (byte) 181; + public static final byte OPC_invokevirtual = (byte) 182; + public static final byte OPC_invokespecial = (byte) 183; + public static final byte OPC_invokestatic = (byte) 184; + public static final byte OPC_invokeinterface = (byte) 185; + public static final byte OPC_new = (byte) 187; + public static final byte OPC_newarray = (byte) 188; + public static final byte OPC_anewarray = (byte) 189; + public static final byte OPC_arraylength = (byte) 190; + public static final byte OPC_athrow = (byte) 191; + public static final byte OPC_checkcast = (byte) 192; + public static final byte OPC_instanceof = (byte) 193; + public static final byte OPC_monitorenter = (byte) 194; + public static final byte OPC_monitorexit = (byte) 195; + public static final byte OPC_wide = (byte) 196; + public static final byte OPC_multianewarray = (byte) 197; + public static final byte OPC_ifnull = (byte) 198; + public static final byte OPC_ifnonnull = (byte) 199; + public static final byte OPC_goto_w = (byte) 200; + public static final byte OPC_jsr_w = (byte) 201; +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/codegen/QualifiedNamesConstants.java b/src/java/org/eclipse/jdt/internal/compiler/codegen/QualifiedNamesConstants.java new file mode 100644 index 0000000..aff4cb8 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/codegen/QualifiedNamesConstants.java @@ -0,0 +1,93 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.codegen; + +public interface QualifiedNamesConstants { + char[] JavaLangObjectConstantPoolName = "java/lang/Object".toCharArray(); //$NON-NLS-1$ + char[] JavaLangStringConstantPoolName = "java/lang/String".toCharArray(); //$NON-NLS-1$ + char[] JavaLangStringBufferConstantPoolName = "java/lang/StringBuffer".toCharArray(); //$NON-NLS-1$ + char[] JavaLangClassConstantPoolName = "java/lang/Class".toCharArray(); //$NON-NLS-1$ + char[] JavaLangThrowableConstantPoolName = "java/lang/Throwable".toCharArray(); //$NON-NLS-1$ + char[] JavaLangClassNotFoundExceptionConstantPoolName = "java/lang/ClassNotFoundException".toCharArray(); //$NON-NLS-1$ + char[] JavaLangNoClassDefFoundErrorConstantPoolName = "java/lang/NoClassDefFoundError".toCharArray(); //$NON-NLS-1$ + char[] JavaLangIntegerConstantPoolName = "java/lang/Integer".toCharArray(); //$NON-NLS-1$ + char[] JavaLangFloatConstantPoolName = "java/lang/Float".toCharArray(); //$NON-NLS-1$ + char[] JavaLangDoubleConstantPoolName = "java/lang/Double".toCharArray(); //$NON-NLS-1$ + char[] JavaLangLongConstantPoolName = "java/lang/Long".toCharArray(); //$NON-NLS-1$ + char[] JavaLangShortConstantPoolName = "java/lang/Short".toCharArray(); //$NON-NLS-1$ + char[] JavaLangByteConstantPoolName = "java/lang/Byte".toCharArray(); //$NON-NLS-1$ + char[] JavaLangCharacterConstantPoolName = "java/lang/Character".toCharArray(); //$NON-NLS-1$ + char[] JavaLangVoidConstantPoolName = "java/lang/Void".toCharArray(); //$NON-NLS-1$ + char[] JavaLangBooleanConstantPoolName = "java/lang/Boolean".toCharArray(); //$NON-NLS-1$ + char[] JavaLangSystemConstantPoolName = "java/lang/System".toCharArray(); //$NON-NLS-1$ + char[] JavaLangErrorConstantPoolName = "java/lang/Error".toCharArray(); //$NON-NLS-1$ + char[] JavaLangExceptionConstantPoolName = "java/lang/Exception".toCharArray(); //$NON-NLS-1$ + char[] JavaLangReflectConstructor = "java/lang/reflect/Constructor".toCharArray(); //$NON-NLS-1$ + char[] Append = new char[] {'a', 'p', 'p', 'e', 'n', 'd'}; + char[] ToString = new char[] {'t', 'o', 'S', 't', 'r', 'i', 'n', 'g'}; + char[] Init = new char[] {'<', 'i', 'n', 'i', 't', '>'}; + char[] Clinit = new char[] {'<', 'c', 'l', 'i', 'n', 'i', 't', '>'}; + char[] ValueOf = new char[] {'v', 'a', 'l', 'u', 'e', 'O', 'f'}; + char[] ForName = new char[] {'f', 'o', 'r', 'N', 'a', 'm', 'e'}; + char[] GetMessage = new char[] {'g', 'e', 't', 'M', 'e', 's', 's', 'a', 'g', 'e'}; + char[] NewInstance = "newInstance".toCharArray(); //$NON-NLS-1$ + char[] GetConstructor = "getConstructor".toCharArray(); //$NON-NLS-1$ + char[] Exit = new char[] {'e', 'x', 'i', 't'}; + char[] Intern = "intern".toCharArray(); //$NON-NLS-1$ + char[] Out = new char[] {'o', 'u', 't'}; + char[] TYPE = new char[] {'T', 'Y', 'P', 'E'}; + char[] This = new char[] {'t', 'h', 'i', 's'}; + char[] JavaLangClassSignature = new char[] {'L', 'j', 'a', 'v', 'a', '/', 'l', 'a', 'n', 'g', '/', 'C', 'l', 'a', 's', 's', ';'}; + char[] ForNameSignature = "(Ljava/lang/String;)Ljava/lang/Class;".toCharArray(); //$NON-NLS-1$ + char[] GetMessageSignature = "()Ljava/lang/String;".toCharArray(); //$NON-NLS-1$ + char[] GetConstructorSignature = "([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;".toCharArray(); //$NON-NLS-1$ + char[] StringConstructorSignature = "(Ljava/lang/String;)V".toCharArray(); //$NON-NLS-1$ + char[] NewInstanceSignature = "([Ljava/lang/Object;)Ljava/lang/Object;".toCharArray(); //$NON-NLS-1$ + char[] DefaultConstructorSignature = {'(', ')', 'V'}; + char[] ClinitSignature = DefaultConstructorSignature; + char[] ToStringSignature = GetMessageSignature; + char[] InternSignature = GetMessageSignature; + char[] AppendIntSignature = "(I)Ljava/lang/StringBuffer;".toCharArray(); //$NON-NLS-1$ + char[] AppendLongSignature = "(J)Ljava/lang/StringBuffer;".toCharArray(); //$NON-NLS-1$ + char[] AppendFloatSignature = "(F)Ljava/lang/StringBuffer;".toCharArray(); //$NON-NLS-1$ + char[] AppendDoubleSignature = "(D)Ljava/lang/StringBuffer;".toCharArray(); //$NON-NLS-1$ + char[] AppendCharSignature = "(C)Ljava/lang/StringBuffer;".toCharArray(); //$NON-NLS-1$ + char[] AppendBooleanSignature = "(Z)Ljava/lang/StringBuffer;".toCharArray(); //$NON-NLS-1$ + char[] AppendObjectSignature = "(Ljava/lang/Object;)Ljava/lang/StringBuffer;".toCharArray(); //$NON-NLS-1$ + char[] AppendStringSignature = "(Ljava/lang/String;)Ljava/lang/StringBuffer;".toCharArray(); //$NON-NLS-1$ + char[] ValueOfObjectSignature = "(Ljava/lang/Object;)Ljava/lang/String;".toCharArray(); //$NON-NLS-1$ + char[] ValueOfIntSignature = "(I)Ljava/lang/String;".toCharArray(); //$NON-NLS-1$ + char[] ValueOfLongSignature = "(J)Ljava/lang/String;".toCharArray(); //$NON-NLS-1$ + char[] ValueOfCharSignature = "(C)Ljava/lang/String;".toCharArray(); //$NON-NLS-1$ + char[] ValueOfBooleanSignature = "(Z)Ljava/lang/String;".toCharArray(); //$NON-NLS-1$ + char[] ValueOfDoubleSignature = "(D)Ljava/lang/String;".toCharArray(); //$NON-NLS-1$ + char[] ValueOfFloatSignature = "(F)Ljava/lang/String;".toCharArray(); //$NON-NLS-1$ + char[] JavaIoPrintStreamSignature = "Ljava/io/PrintStream;".toCharArray(); //$NON-NLS-1$ + char[] ExitIntSignature = new char[] {'(', 'I', ')', 'V'}; + char[] ArrayJavaLangObjectConstantPoolName = "[Ljava/lang/Object;".toCharArray(); //$NON-NLS-1$ + char[] ArrayJavaLangClassConstantPoolName = "[Ljava/lang/Class;".toCharArray(); //$NON-NLS-1$ + char[] JavaLangAssertionErrorConstantPoolName = "java/lang/AssertionError".toCharArray(); //$NON-NLS-1$ + char[] AssertionErrorIntConstrSignature = "(I)V".toCharArray(); //$NON-NLS-1$ + char[] AssertionErrorLongConstrSignature = "(J)V".toCharArray(); //$NON-NLS-1$ + char[] AssertionErrorFloatConstrSignature = "(F)V".toCharArray(); //$NON-NLS-1$ + char[] AssertionErrorDoubleConstrSignature = "(D)V".toCharArray(); //$NON-NLS-1$ + char[] AssertionErrorCharConstrSignature = "(C)V".toCharArray(); //$NON-NLS-1$ + char[] AssertionErrorBooleanConstrSignature = "(Z)V".toCharArray(); //$NON-NLS-1$ + char[] AssertionErrorObjectConstrSignature = "(Ljava/lang/Object;)V".toCharArray(); //$NON-NLS-1$ + char[] DesiredAssertionStatus = "desiredAssertionStatus".toCharArray(); //$NON-NLS-1$ + char[] DesiredAssertionStatusSignature = "()Z".toCharArray(); //$NON-NLS-1$ + char[] ShortConstrSignature = "(S)V".toCharArray(); //$NON-NLS-1$ + char[] ByteConstrSignature = "(B)V".toCharArray(); //$NON-NLS-1$ + char[] GetClass = "getClass".toCharArray(); //$NON-NLS-1$ + char[] GetClassSignature = "()Ljava/lang/Class;".toCharArray(); //$NON-NLS-1$ + char[] GetComponentType = "getComponentType".toCharArray(); //$NON-NLS-1$ + char[] GetComponentTypeSignature = GetClassSignature; +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/env/IBinaryField.java b/src/java/org/eclipse/jdt/internal/compiler/env/IBinaryField.java new file mode 100644 index 0000000..d928f82 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/env/IBinaryField.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.env; + +import org.eclipse.jdt.internal.compiler.impl.Constant; + +public interface IBinaryField extends IGenericField { +/** + * + * @return org.eclipse.jdt.internal.compiler.Constant + */ +Constant getConstant(); +/** + * Answer the resolved name of the receiver's type in the + * class file format as specified in section 4.3.2 of the Java 2 VM spec. + * + * For example: + * - java.lang.String is Ljava/lang/String; + * - an int is I + * - a 2 dimensional array of strings is [[Ljava/lang/String; + * - an array of floats is [F + */ + +char[] getTypeName(); +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/env/IBinaryMethod.java b/src/java/org/eclipse/jdt/internal/compiler/env/IBinaryMethod.java new file mode 100644 index 0000000..75435bc --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/env/IBinaryMethod.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.env; + +// clinit methods (synthetics too?) can be returned from IBinaryType>>getMethods() +// BUT do not have to be... the compiler will ignore them when building the binding. +// The synthetic argument of a member type's constructor (ie. the first arg of a non-static +// member type) is also ignored by the compiler, BUT in this case it must be included +// in the constructor's signature. + +public interface IBinaryMethod extends IGenericMethod { + +/** + * Answer the resolved names of the exception types in the + * class file format as specified in section 4.2 of the Java 2 VM spec + * or null if the array is empty. + * + * For example, java.lang.String is java/lang/String. + */ +char[][] getExceptionTypeNames(); + +/** + * Answer the receiver's method descriptor which describes the parameter & + * return types as specified in section 4.3.3 of the Java 2 VM spec. + * + * For example: + * - int foo(String) is (Ljava/lang/String;)I + * - Object[] foo(int) is (I)[Ljava/lang/Object; + */ +char[] getMethodDescriptor(); + +/** + * Answer whether the receiver represents a class initializer method. + */ +boolean isClinit(); +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/env/IBinaryNestedType.java b/src/java/org/eclipse/jdt/internal/compiler/env/IBinaryNestedType.java new file mode 100644 index 0000000..8a781dc --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/env/IBinaryNestedType.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.env; + +public interface IBinaryNestedType { +/** + * Answer the resolved name of the enclosing type in the + * class file format as specified in section 4.2 of the Java 2 VM spec. + * + * For example, java.lang.String is java/lang/String. + */ + +char[] getEnclosingTypeName(); +/** + * Answer an int whose bits are set according the access constants + * defined by the VM spec. + */ + +// We have added AccDeprecated & AccSynthetic. + +int getModifiers(); +/** + * Answer the resolved name of the member type in the + * class file format as specified in section 4.2 of the Java 2 VM spec. + * + * For example, p1.p2.A.M is p1/p2/A$M. + */ + +char[] getName(); +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/env/IBinaryType.java b/src/java/org/eclipse/jdt/internal/compiler/env/IBinaryType.java new file mode 100644 index 0000000..aacda73 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/env/IBinaryType.java @@ -0,0 +1,104 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.env; + +import org.eclipse.jdt.core.compiler.CharOperation; + +public interface IBinaryType extends IGenericType { + + char[][] NoInterface = CharOperation.NO_CHAR_CHAR; + IBinaryNestedType[] NoNestedType = new IBinaryNestedType[0]; + IBinaryField[] NoField = new IBinaryField[0]; + IBinaryMethod[] NoMethod = new IBinaryMethod[0]; +/** + * Answer the resolved name of the enclosing type in the + * class file format as specified in section 4.2 of the Java 2 VM spec + * or null if the receiver is a top level type. + * + * For example, java.lang.String is java/lang/String. + */ + +char[] getEnclosingTypeName(); +/** + * Answer the receiver's fields or null if the array is empty. + */ + +IBinaryField[] getFields(); +/** + * Answer the resolved names of the receiver's interfaces in the + * class file format as specified in section 4.2 of the Java 2 VM spec + * or null if the array is empty. + * + * For example, java.lang.String is java/lang/String. + */ + +char[][] getInterfaceNames(); +/** + * Answer the receiver's nested types or null if the array is empty. + * + * This nested type info is extracted from the inner class attributes. + * Ask the name environment to find a member type using its compound name. + */ + +// NOTE: The compiler examines the nested type info & ignores the local types +// so the local types do not have to be included. + +IBinaryNestedType[] getMemberTypes(); +/** + * Answer the receiver's methods or null if the array is empty. + */ + +IBinaryMethod[] getMethods(); +/** + * Answer the resolved name of the type in the + * class file format as specified in section 4.2 of the Java 2 VM spec. + * + * For example, java.lang.String is java/lang/String. + */ + +char[] getName(); +/** + * Answer the resolved name of the receiver's superclass in the + * class file format as specified in section 4.2 of the Java 2 VM spec + * or null if it does not have one. + * + * For example, java.lang.String is java/lang/String. + */ + +char[] getSuperclassName(); + +/** + * Answer true if the receiver is an anonymous class. + * false otherwise + */ +boolean isAnonymous(); + +/** + * Answer true if the receiver is a local class. + * false otherwise + */ +boolean isLocal(); + +/** + * Answer true if the receiver is a member class. + * false otherwise + */ +boolean isMember(); + +/** + * Answer the source file attribute, or null if none. + * + * For example, "String.java" + */ + +char[] sourceFileName(); + +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/env/ICompilationUnit.java b/src/java/org/eclipse/jdt/internal/compiler/env/ICompilationUnit.java new file mode 100644 index 0000000..bbcef08 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/env/ICompilationUnit.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.env; + +/** + * This interface denotes a compilation unit, providing its name and content. + */ +public interface ICompilationUnit extends IDependent { +/** + * Answer the contents of the compilation unit. + * + * In normal use, the contents are requested twice. + * Once during the initial lite parsing step, then again for the + * more detailed parsing step. + */ +char[] getContents(); +/** + * Answer the name of the top level public type. + * For example, {Hashtable}. + */ +char[] getMainTypeName(); +/** + * Answer the name of the package according to the directory structure + * or null if package consistency checks should be ignored. + * For example, {java, lang}. + */ +char[][] getPackageName(); +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/env/IConstants.java b/src/java/org/eclipse/jdt/internal/compiler/env/IConstants.java new file mode 100644 index 0000000..4f3bfa1 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/env/IConstants.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.env; + +/** + * This interface defines constants for use by the builder / compiler interface. + */ +public interface IConstants { + + int AccDefault = 0; + + /** + * Modifiers + */ + int AccPublic = 0x0001; + int AccPrivate = 0x0002; + int AccProtected = 0x0004; + int AccStatic = 0x0008; + int AccFinal = 0x0010; + int AccSynchronized = 0x0020; + int AccVolatile = 0x0040; + int AccBridge = 0x0040; + int AccTransient = 0x0080; + int AccVarargs = 0x0080; + int AccNative = 0x0100; + int AccInterface = 0x0200; + int AccAbstract = 0x0400; + int AccStrictfp = 0x0800; + int AccSynthetic = 0x1000; + + /** + * Other VM flags. + */ + int AccSuper = 0x0020; + + /** + * Extra flags for types and members attributes. + */ + int AccDeprecated = 0x100000; + +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/env/IDependent.java b/src/java/org/eclipse/jdt/internal/compiler/env/IDependent.java new file mode 100644 index 0000000..bf645ec --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/env/IDependent.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.env; + +/** + * This represents the target file of a type dependency. + * + * All implementors of this interface are containers for types or types + * themselves which must be able to identify their source file name + * when file dependencies are collected. + */ +public interface IDependent { +/** + * Answer the file name which defines the type. + * + * The path part (optional) must be separated from the actual + * file proper name by a java.io.File.separator. + * + * The proper file name includes the suffix extension (e.g. ".java") + * + * e.g. "c:/com/ibm/compiler/java/api/Compiler.java" + */ + +char[] getFileName(); +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/env/IGenericField.java b/src/java/org/eclipse/jdt/internal/compiler/env/IGenericField.java new file mode 100644 index 0000000..35684a0 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/env/IGenericField.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.env; + +public interface IGenericField { +/** + * Answer an int whose bits are set according the access constants + * defined by the VM spec. + */ + +// We have added AccDeprecated & AccSynthetic. + +int getModifiers(); +/** + * Answer the name of the field. + */ + +char[] getName(); +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/env/IGenericMethod.java b/src/java/org/eclipse/jdt/internal/compiler/env/IGenericMethod.java new file mode 100644 index 0000000..c742d2d --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/env/IGenericMethod.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.env; + +public interface IGenericMethod { +/** + * Answer an int whose bits are set according the access constants + * defined by the VM spec. + */ +// We have added AccDeprecated +int getModifiers(); + +/** + * Answer the name of the method. + * + * For a constructor, answer & for a clinit method. + */ +char[] getSelector(); + +boolean isConstructor(); + +/** + * Answer the names of the argument + * or null if the argument names are not available. + */ + +char[][] getArgumentNames(); +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/env/IGenericType.java b/src/java/org/eclipse/jdt/internal/compiler/env/IGenericType.java new file mode 100644 index 0000000..cca5c60 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/env/IGenericType.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.env; + +public interface IGenericType extends IDependent { +/** + * Answer an int whose bits are set according the access constants + * defined by the VM spec. + */ + +// We have added AccDeprecated & AccSynthetic. + +// NOTE: If the receiver represents a member type, the modifiers are extracted from its inner class attributes. + +int getModifiers(); +/** + * Answer whether the receiver contains the resolved binary form + * or the unresolved source form of the type. + */ + +boolean isBinaryType(); +boolean isClass(); +boolean isInterface(); +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/env/INameEnvironment.java b/src/java/org/eclipse/jdt/internal/compiler/env/INameEnvironment.java new file mode 100644 index 0000000..0005601 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/env/INameEnvironment.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.env; + +/** + * The name environment provides a callback API that the compiler + * can use to look up types, compilation units, and packages in the + * current environment. The name environment is passed to the compiler + * on creation. + */ +public interface INameEnvironment { +/** + * Find a type with the given compound name. + * Answer the binary form of the type if it is known to be consistent. + * Otherwise, answer the compilation unit which defines the type + * or null if the type does not exist. + * Types in the default package are specified as {{typeName}}. + * + * It is unknown whether the package containing the type actually exists. + * + * NOTE: This method can be used to find a member type using its + * internal name A$B, but the source file for A is answered if the binary + * file is inconsistent. + */ + +NameEnvironmentAnswer findType(char[][] compoundTypeName); +/** + * Find a type named in the package . + * Answer the binary form of the type if it is known to be consistent. + * Otherwise, answer the compilation unit which defines the type + * or null if the type does not exist. + * The default package is indicated by char[0][]. + * + * It is known that the package containing the type exists. + * + * NOTE: This method can be used to find a member type using its + * internal name A$B, but the source file for A is answered if the binary + * file is inconsistent. + */ + +NameEnvironmentAnswer findType(char[] typeName, char[][] packageName); +/** + * Answer whether packageName is the name of a known subpackage inside + * the package parentPackageName. A top level package is found relative to null. + * The default package is always assumed to exist. + * + * For example: + * isPackage({{java}, {awt}}, {event}); + * isPackage(null, {java}); + */ + +boolean isPackage(char[][] parentPackageName, char[] packageName); + +/** + * This method cleans the environment uo. It is responsible for releasing the memory + * and freeing resources. Passed that point, the name environment is no longer usable. + * + * A name environment can have a long life cycle, therefore it is the responsibility of + * the code which created it to decide when it is a good time to clean it up. + */ +void cleanup(); + +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/env/ISourceField.java b/src/java/org/eclipse/jdt/internal/compiler/env/ISourceField.java new file mode 100644 index 0000000..a344384 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/env/ISourceField.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.env; + +public interface ISourceField extends IGenericField { +/** + * Answer the source end position of the field's declaration. + */ +int getDeclarationSourceEnd(); + +/** + * Answer the source start position of the field's declaration. + */ +int getDeclarationSourceStart(); + +/** + * Answer the initialization source for this constant field. + * Answer null if the field is not a constant or if it has no initialization. + */ +char[] getInitializationSource(); + +/** + * Answer the source end position of the field's name. + */ +int getNameSourceEnd(); + +/** + * Answer the source start position of the field's name. + */ +int getNameSourceStart(); + +/** + * Answer the type name of the field. + * + * The name is a simple name or a qualified, dot separated name. + * For example, Hashtable or java.util.Hashtable. + */ +char[] getTypeName(); +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/env/ISourceImport.java b/src/java/org/eclipse/jdt/internal/compiler/env/ISourceImport.java new file mode 100644 index 0000000..5bbd9bc --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/env/ISourceImport.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.env; + +public interface ISourceImport { + +/** + * Answer the source end position of the import declaration. + */ + +int getDeclarationSourceEnd(); +/** + * Answer the source start position of the import declaration. + */ + +int getDeclarationSourceStart(); + +/** + * Answer an int whose bits are set according the access constants + * defined by the VM spec. + * Since Java 1.5, static imports can be defined. + */ +int getModifiers(); + +/** + * Answer the name of the import. + * A name is a simple name or a qualified, dot separated name. + * For example, Hashtable or java.util.Hashtable. + */ +char[] getName(); + +/** + * Answer whether the import is on demand or not + * On demand import names have no trailing star + */ +boolean onDemand(); +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/env/ISourceMethod.java b/src/java/org/eclipse/jdt/internal/compiler/env/ISourceMethod.java new file mode 100644 index 0000000..fc08366 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/env/ISourceMethod.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.env; + +public interface ISourceMethod extends IGenericMethod { + +/** + * Answer the unresolved names of the argument types + * or null if the array is empty. + * + * A name is a simple name or a qualified, dot separated name. + * For example, Hashtable or java.util.Hashtable. + */ + +char[][] getArgumentTypeNames(); +/** + * Answer the source end position of the method's declaration. + */ + +int getDeclarationSourceEnd(); +/** + * Answer the source start position of the method's declaration. + */ + +int getDeclarationSourceStart(); +/** + * Answer the unresolved names of the exception types + * or null if the array is empty. + * + * A name is a simple name or a qualified, dot separated name. + * For example, Hashtable or java.util.Hashtable. + */ + +char[][] getExceptionTypeNames(); +/** + * Answer the source end position of the method's selector. + */ + +int getNameSourceEnd(); +/** + * Answer the source start position of the method's selector. + */ + +int getNameSourceStart(); +/** + * Answer the unresolved name of the return type + * or null if receiver is a constructor or clinit. + * + * The name is a simple name or a qualified, dot separated name. + * For example, Hashtable or java.util.Hashtable. + */ + +char[] getReturnTypeName(); +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/env/ISourceType.java b/src/java/org/eclipse/jdt/internal/compiler/env/ISourceType.java new file mode 100644 index 0000000..594d718 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/env/ISourceType.java @@ -0,0 +1,101 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.env; + +public interface ISourceType extends IGenericType { + +/** + * Answer the source end position of the type's declaration. + */ +int getDeclarationSourceEnd(); + +/** + * Answer the source start position of the type's declaration. + */ +int getDeclarationSourceStart(); + +/** + * Answer the enclosing type + * or null if the receiver is a top level type. + */ +ISourceType getEnclosingType(); + +/** + * Answer the receiver's fields or null if the array is empty. + * + * NOTE: Multiple fields with the same name can exist in the result. + */ +ISourceField[] getFields(); + +/** + * Answer the receiver's imports or null if the array is empty. + * + * An import is a qualified, dot separated name. + * For example, java.util.Hashtable or java.lang.*. + * A static import used 'static.' as its first fragment, for + * example: static.java.util.Hashtable.* + */ +ISourceImport[] getImports(); + +/** + * Answer the unresolved names of the receiver's interfaces + * or null if the array is empty. + * + * A name is a simple name or a qualified, dot separated name. + * For example, Hashtable or java.util.Hashtable. + */ +char[][] getInterfaceNames(); + +/** + * Answer the receiver's member types + * or null if the array is empty. + */ +ISourceType[] getMemberTypes(); + +/** + * Answer the receiver's methods or null if the array is empty. + * + * NOTE: Multiple methods with the same name & parameter types can exist in the result. + */ +ISourceMethod[] getMethods(); + +/** + * Answer the simple source name of the receiver. + */ +char[] getName(); + +/** + * Answer the source end position of the type's name. + */ +int getNameSourceEnd(); + +/** + * Answer the source start position of the type's name. + */ +int getNameSourceStart(); + +/** + * Answer the qualified name of the receiver's package separated by periods + * or null if its the default package. + * + * For example, {java.util.Hashtable}. + */ +char[] getPackageName(); + +/** + * Answer the unresolved name of the receiver's superclass + * or null if it does not have one. + * + * The name is a simple name or a qualified, dot separated name. + * For example, Hashtable or java.util.Hashtable. + */ +char[] getSuperclassName(); +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/env/NameEnvironmentAnswer.java b/src/java/org/eclipse/jdt/internal/compiler/env/NameEnvironmentAnswer.java new file mode 100644 index 0000000..b7ab4e6 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/env/NameEnvironmentAnswer.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.env; + +public class NameEnvironmentAnswer { + + // only one of the three can be set + IBinaryType binaryType; + ICompilationUnit compilationUnit; + ISourceType[] sourceTypes; + + public NameEnvironmentAnswer(IBinaryType binaryType) { + this.binaryType = binaryType; + } + + public NameEnvironmentAnswer(ICompilationUnit compilationUnit) { + this.compilationUnit = compilationUnit; + } + + public NameEnvironmentAnswer(ISourceType[] sourceTypes) { + this.sourceTypes = sourceTypes; + } + + /** + * Answer the resolved binary form for the type or null if the + * receiver represents a compilation unit or source type. + */ + public IBinaryType getBinaryType() { + return this.binaryType; + } + + /** + * Answer the compilation unit or null if the + * receiver represents a binary or source type. + */ + public ICompilationUnit getCompilationUnit() { + return this.compilationUnit; + } + + /** + * Answer the unresolved source forms for the type or null if the + * receiver represents a compilation unit or binary type. + * + * Multiple source forms can be answered in case the originating compilation unit did contain + * several type at once. Then the first type is guaranteed to be the requested type. + */ + public ISourceType[] getSourceTypes() { + return this.sourceTypes; + } + + /** + * Answer whether the receiver contains the resolved binary form of the type. + */ + public boolean isBinaryType() { + return this.binaryType != null; + } + + /** + * Answer whether the receiver contains the compilation unit which defines the type. + */ + public boolean isCompilationUnit() { + return this.compilationUnit != null; + } + + /** + * Answer whether the receiver contains the unresolved source form of the type. + */ + public boolean isSourceType() { + return this.sourceTypes != null; + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java b/src/java/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java new file mode 100644 index 0000000..115979e --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java @@ -0,0 +1,178 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.flow; + +import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; +import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; + +/** + * Record conditional initialization status during definite assignment analysis + * + */ +public class ConditionalFlowInfo extends FlowInfo { + + public FlowInfo initsWhenTrue; + public FlowInfo initsWhenFalse; + + ConditionalFlowInfo(FlowInfo initsWhenTrue, FlowInfo initsWhenFalse){ + + this.initsWhenTrue = initsWhenTrue; + this.initsWhenFalse = initsWhenFalse; + } + + public FlowInfo addInitializationsFrom(FlowInfo otherInits) { + + this.initsWhenTrue.addInitializationsFrom(otherInits); + this.initsWhenFalse.addInitializationsFrom(otherInits); + return this; + } + + public FlowInfo addPotentialInitializationsFrom(FlowInfo otherInits) { + + this.initsWhenTrue.addPotentialInitializationsFrom(otherInits); + this.initsWhenFalse.addPotentialInitializationsFrom(otherInits); + return this; + } + + public FlowInfo asNegatedCondition() { + + FlowInfo extra = initsWhenTrue; + initsWhenTrue = initsWhenFalse; + initsWhenFalse = extra; + return this; + } + + public FlowInfo copy() { + + return new ConditionalFlowInfo(initsWhenTrue.copy(), initsWhenFalse.copy()); + } + + public FlowInfo initsWhenFalse() { + + return initsWhenFalse; + } + + public FlowInfo initsWhenTrue() { + + return initsWhenTrue; + } + + /** + * Check status of definite assignment for a field. + */ + public boolean isDefinitelyAssigned(FieldBinding field) { + + return initsWhenTrue.isDefinitelyAssigned(field) + && initsWhenFalse.isDefinitelyAssigned(field); + } + + /** + * Check status of definite assignment for a local variable. + */ + public boolean isDefinitelyAssigned(LocalVariableBinding local) { + + return initsWhenTrue.isDefinitelyAssigned(local) + && initsWhenFalse.isDefinitelyAssigned(local); + } + + public int reachMode(){ + return unconditionalInits().reachMode(); + } + + public boolean isReachable(){ + + return unconditionalInits().isReachable(); + //should maybe directly be: false + } + + /** + * Check status of potential assignment for a field. + */ + public boolean isPotentiallyAssigned(FieldBinding field) { + + return initsWhenTrue.isPotentiallyAssigned(field) + || initsWhenFalse.isPotentiallyAssigned(field); + } + + /** + * Check status of potential assignment for a local variable. + */ + public boolean isPotentiallyAssigned(LocalVariableBinding local) { + + return initsWhenTrue.isPotentiallyAssigned(local) + || initsWhenFalse.isPotentiallyAssigned(local); + } + + /** + * Record a field got definitely assigned. + */ + public void markAsDefinitelyAssigned(FieldBinding field) { + + initsWhenTrue.markAsDefinitelyAssigned(field); + initsWhenFalse.markAsDefinitelyAssigned(field); + } + + /** + * Record a field got definitely assigned. + */ + public void markAsDefinitelyAssigned(LocalVariableBinding local) { + + initsWhenTrue.markAsDefinitelyAssigned(local); + initsWhenFalse.markAsDefinitelyAssigned(local); + } + + /** + * Clear the initialization info for a field + */ + public void markAsDefinitelyNotAssigned(FieldBinding field) { + + initsWhenTrue.markAsDefinitelyNotAssigned(field); + initsWhenFalse.markAsDefinitelyNotAssigned(field); + } + + /** + * Clear the initialization info for a local variable + */ + public void markAsDefinitelyNotAssigned(LocalVariableBinding local) { + + initsWhenTrue.markAsDefinitelyNotAssigned(local); + initsWhenFalse.markAsDefinitelyNotAssigned(local); + } + + public FlowInfo setReachMode(int reachMode) { + + initsWhenTrue.setReachMode(reachMode); + initsWhenFalse.setReachMode(reachMode); + return this; + } + + /** + * Converts conditional receiver into inconditional one, updated in the following way:
    + *
  • intersection of definitely assigned variables, + *
  • union of potentially assigned variables. + *
+ */ + public UnconditionalFlowInfo mergedWith(UnconditionalFlowInfo otherInits) { + + return unconditionalInits().mergedWith(otherInits); + } + + public String toString() { + + return "FlowInfo"; //$NON-NLS-1$ //$NON-NLS-3$ //$NON-NLS-2$ + } + + public UnconditionalFlowInfo unconditionalInits() { + + return initsWhenTrue.unconditionalInits().copy() + .mergedWith(initsWhenFalse.unconditionalInits()); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java b/src/java/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java new file mode 100644 index 0000000..4862742 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java @@ -0,0 +1,219 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.flow; + +import java.util.ArrayList; + +import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.ASTNode; +import org.eclipse.jdt.internal.compiler.ast.TryStatement; +import org.eclipse.jdt.internal.compiler.codegen.ObjectCache; +import org.eclipse.jdt.internal.compiler.lookup.BlockScope; +import org.eclipse.jdt.internal.compiler.lookup.CompilerModifiers; +import org.eclipse.jdt.internal.compiler.lookup.MethodScope; +import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; +import org.eclipse.jdt.internal.compiler.lookup.Scope; +import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; + +/** + * Reflects the context of code analysis, keeping track of enclosing + * try statements, exception handlers, etc... + */ +public class ExceptionHandlingFlowContext extends FlowContext { + + public ReferenceBinding[] handledExceptions; + + public final static int BitCacheSize = 32; // 32 bits per int + int[] isReached; + int[] isNeeded; + UnconditionalFlowInfo[] initsOnExceptions; + ObjectCache indexes = new ObjectCache(); + boolean isMethodContext; + + public UnconditionalFlowInfo initsOnReturn; + + // for dealing with anonymous constructor thrown exceptions + public ArrayList extendedExceptions; + + public ExceptionHandlingFlowContext( + FlowContext parent, + ASTNode associatedNode, + ReferenceBinding[] handledExceptions, + BlockScope scope, + UnconditionalFlowInfo flowInfo) { + + super(parent, associatedNode); + isMethodContext = scope == scope.methodScope(); + this.handledExceptions = handledExceptions; + int count = handledExceptions.length, cacheSize = (count / BitCacheSize) + 1; + this.isReached = new int[cacheSize]; // none is reached by default + this.isNeeded = new int[cacheSize]; // none is needed by default + this.initsOnExceptions = new UnconditionalFlowInfo[count]; + for (int i = 0; i < count; i++) { + this.indexes.put(handledExceptions[i], i); // key type -> value index + boolean isUnchecked = + (scope.compareUncheckedException(handledExceptions[i]) != NotRelated); + int cacheIndex = i / BitCacheSize, bitMask = 1 << (i % BitCacheSize); + if (isUnchecked) { + isReached[cacheIndex] |= bitMask; + this.initsOnExceptions[i] = flowInfo.copy().unconditionalInits(); + } else { + this.initsOnExceptions[i] = FlowInfo.DEAD_END; + } + } + System.arraycopy(this.isReached, 0, this.isNeeded, 0, cacheSize); + this.initsOnReturn = FlowInfo.DEAD_END; + } + + public void complainIfUnusedExceptionHandlers(AbstractMethodDeclaration method) { + MethodScope scope = method.scope; + // can optionally skip overriding methods + if ((method.binding.modifiers & (CompilerModifiers.AccOverriding | CompilerModifiers.AccImplementing)) != 0 + && !scope.environment().options.reportUnusedDeclaredThrownExceptionWhenOverriding) { + return; + } + + // report errors for unreachable exception handlers + for (int i = 0, count = handledExceptions.length; i < count; i++) { + int index = indexes.get(handledExceptions[i]); + int cacheIndex = index / BitCacheSize; + int bitMask = 1 << (index % BitCacheSize); + if ((isReached[cacheIndex] & bitMask) == 0) { + scope.problemReporter().unusedDeclaredThrownException( + handledExceptions[index], + method, + method.thrownExceptions[index]); + } + } + } + + public void complainIfUnusedExceptionHandlers( + BlockScope scope, + TryStatement tryStatement) { + // report errors for unreachable exception handlers + for (int i = 0, count = handledExceptions.length; i < count; i++) { + int index = indexes.get(handledExceptions[i]); + int cacheIndex = index / BitCacheSize; + int bitMask = 1 << (index % BitCacheSize); + if ((isReached[cacheIndex] & bitMask) == 0) { + scope.problemReporter().unreachableCatchBlock( + handledExceptions[index], + tryStatement.catchArguments[index].type); + } else { + if ((isNeeded[cacheIndex] & bitMask) == 0) { + scope.problemReporter().hiddenCatchBlock( + handledExceptions[index], + tryStatement.catchArguments[index].type); + } + } + } + } + + public String individualToString() { + + StringBuffer buffer = new StringBuffer("Exception flow context"); //$NON-NLS-1$ + int length = handledExceptions.length; + for (int i = 0; i < length; i++) { + int cacheIndex = i / BitCacheSize; + int bitMask = 1 << (i % BitCacheSize); + buffer.append('[').append(handledExceptions[i].readableName()); + if ((isReached[cacheIndex] & bitMask) != 0) { + if ((isNeeded[cacheIndex] & bitMask) == 0) { + buffer.append("-masked"); //$NON-NLS-1$ + } else { + buffer.append("-reached"); //$NON-NLS-1$ + } + } else { + buffer.append("-not reached"); //$NON-NLS-1$ + } + buffer.append('-').append(initsOnExceptions[i].toString()).append(']'); + } + buffer.append("[initsOnReturn -").append(initsOnReturn.toString()).append(']'); //$NON-NLS-1$ + return buffer.toString(); + } + + public UnconditionalFlowInfo initsOnException(ReferenceBinding exceptionType) { + + int index; + if ((index = indexes.get(exceptionType)) < 0) { + return FlowInfo.DEAD_END; + } + return initsOnExceptions[index]; + } + + public UnconditionalFlowInfo initsOnReturn(){ + return this.initsOnReturn; + } + + public void recordHandlingException( + ReferenceBinding exceptionType, + UnconditionalFlowInfo flowInfo, + TypeBinding raisedException, + ASTNode invocationSite, + boolean wasAlreadyDefinitelyCaught) { + + int index = indexes.get(exceptionType); + // if already flagged as being reached (unchecked exception handler) + int cacheIndex = index / BitCacheSize; + int bitMask = 1 << (index % BitCacheSize); + if (!wasAlreadyDefinitelyCaught) { + this.isNeeded[cacheIndex] |= bitMask; + } + this.isReached[cacheIndex] |= bitMask; + + initsOnExceptions[index] = + initsOnExceptions[index] == FlowInfo.DEAD_END + ? flowInfo.copy().unconditionalInits() + : initsOnExceptions[index].mergedWith(flowInfo.copy().unconditionalInits()); + } + + public void recordReturnFrom(FlowInfo flowInfo) { + + if (!flowInfo.isReachable()) return; + if (initsOnReturn == FlowInfo.DEAD_END) { + initsOnReturn = flowInfo.copy().unconditionalInits(); + } else { + initsOnReturn = initsOnReturn.mergedWith(flowInfo.copy().unconditionalInits()); + } + } + + /* + * Compute a merged list of unhandled exception types (keeping only the most generic ones). + * This is necessary to add synthetic thrown exceptions for anonymous type constructors (JLS 8.6). + */ + public void mergeUnhandledException(TypeBinding newException){ + + if (this.extendedExceptions == null){ + this.extendedExceptions = new ArrayList(5); + for (int i = 0; i < this.handledExceptions.length; i++){ + this.extendedExceptions.add(this.handledExceptions[i]); + } + } + + boolean isRedundant = false; + + for(int i = this.extendedExceptions.size()-1; i >= 0; i--){ + switch(Scope.compareTypes(newException, (TypeBinding)this.extendedExceptions.get(i))){ + case MoreGeneric : + this.extendedExceptions.remove(i); + break; + case EqualOrMoreSpecific : + isRedundant = true; + break; + case NotRelated : + break; + } + } + if (!isRedundant){ + this.extendedExceptions.add(newException); + } + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/flow/FinallyFlowContext.java b/src/java/org/eclipse/jdt/internal/compiler/flow/FinallyFlowContext.java new file mode 100644 index 0000000..d17ab89 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/flow/FinallyFlowContext.java @@ -0,0 +1,122 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.flow; + +import org.eclipse.jdt.internal.compiler.ast.ASTNode; +import org.eclipse.jdt.internal.compiler.ast.Reference; +import org.eclipse.jdt.internal.compiler.lookup.BlockScope; +import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; +import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; +import org.eclipse.jdt.internal.compiler.lookup.VariableBinding; + +/** + * Reflects the context of code analysis, keeping track of enclosing + * try statements, exception handlers, etc... + */ +public class FinallyFlowContext extends FlowContext { + + Reference finalAssignments[]; + VariableBinding finalVariables[]; + int assignCount; + + public FinallyFlowContext(FlowContext parent, ASTNode associatedNode) { + super(parent, associatedNode); + } + + /** + * Given some contextual initialization info (derived from a try block or a catch block), this + * code will check that the subroutine context does not also initialize a final variable potentially set + * redundantly. + */ + public void complainOnRedundantFinalAssignments( + FlowInfo flowInfo, + BlockScope scope) { + for (int i = 0; i < assignCount; i++) { + VariableBinding variable = finalVariables[i]; + if (variable == null) continue; + + boolean complained = false; // remember if have complained on this final assignment + if (variable instanceof FieldBinding) { + // final field + if (flowInfo.isPotentiallyAssigned((FieldBinding)variable)) { + complained = true; + scope.problemReporter().duplicateInitializationOfBlankFinalField((FieldBinding)variable, finalAssignments[i]); + } + } else { + // final local variable + if (flowInfo.isPotentiallyAssigned((LocalVariableBinding) variable)) { + complained = true; + scope.problemReporter().duplicateInitializationOfFinalLocal( + (LocalVariableBinding) variable, + finalAssignments[i]); + } + } + // any reference reported at this level is removed from the parent context + // where it could also be reported again + if (complained) { + FlowContext currentContext = parent; + while (currentContext != null) { + //if (currentContext.isSubRoutine()) { + currentContext.removeFinalAssignmentIfAny(finalAssignments[i]); + //} + currentContext = currentContext.parent; + } + } + } + } + + public String individualToString() { + + StringBuffer buffer = new StringBuffer("Finally flow context"); //$NON-NLS-1$ + buffer.append("[finalAssignments count -").append(assignCount).append(']'); //$NON-NLS-1$ + return buffer.toString(); + } + + public boolean isSubRoutine() { + return true; + } + + boolean recordFinalAssignment( + VariableBinding binding, + Reference finalAssignment) { + if (assignCount == 0) { + finalAssignments = new Reference[5]; + finalVariables = new VariableBinding[5]; + } else { + if (assignCount == finalAssignments.length) + System.arraycopy( + finalAssignments, + 0, + (finalAssignments = new Reference[assignCount * 2]), + 0, + assignCount); + System.arraycopy( + finalVariables, + 0, + (finalVariables = new VariableBinding[assignCount * 2]), + 0, + assignCount); + } + finalAssignments[assignCount] = finalAssignment; + finalVariables[assignCount++] = binding; + return true; + } + + void removeFinalAssignmentIfAny(Reference reference) { + for (int i = 0; i < assignCount; i++) { + if (finalAssignments[i] == reference) { + finalAssignments[i] = null; + finalVariables[i] = null; + return; + } + } + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/flow/FlowContext.java b/src/java/org/eclipse/jdt/internal/compiler/flow/FlowContext.java new file mode 100644 index 0000000..340781f --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/flow/FlowContext.java @@ -0,0 +1,493 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.flow; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.ASTNode; +import org.eclipse.jdt.internal.compiler.ast.Reference; +import org.eclipse.jdt.internal.compiler.ast.SubRoutineStatement; +import org.eclipse.jdt.internal.compiler.ast.TryStatement; +import org.eclipse.jdt.internal.compiler.codegen.Label; +import org.eclipse.jdt.internal.compiler.lookup.BlockScope; +import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; +import org.eclipse.jdt.internal.compiler.lookup.Scope; +import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; +import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; +import org.eclipse.jdt.internal.compiler.lookup.VariableBinding; + +/** + * Reflects the context of code analysis, keeping track of enclosing + * try statements, exception handlers, etc... + */ +public class FlowContext implements TypeConstants { + + public ASTNode associatedNode; + public FlowContext parent; + + public final static FlowContext NotContinuableContext = new FlowContext(null, null); + + public FlowContext(FlowContext parent, ASTNode associatedNode) { + + this.parent = parent; + this.associatedNode = associatedNode; + } + + public Label breakLabel() { + + return null; + } + + public void checkExceptionHandlers( + TypeBinding[] raisedExceptions, + ASTNode location, + FlowInfo flowInfo, + BlockScope scope) { + + // check that all the argument exception types are handled + // JDK Compatible implementation - when an exception type is thrown, + // all related catch blocks are marked as reachable... instead of those only + // until the point where it is safely handled (Smarter - see comment at the end) + int remainingCount; // counting the number of remaining unhandled exceptions + int raisedCount; // total number of exceptions raised + if ((raisedExceptions == null) + || ((raisedCount = raisedExceptions.length) == 0)) + return; + remainingCount = raisedCount; + + // duplicate the array of raised exceptions since it will be updated + // (null replaces any handled exception) + System.arraycopy( + raisedExceptions, + 0, + (raisedExceptions = new TypeBinding[raisedCount]), + 0, + raisedCount); + FlowContext traversedContext = this; + + while (traversedContext != null) { + SubRoutineStatement sub; + if (((sub = traversedContext.subRoutine()) != null) && sub.isSubRoutineEscaping()) { + // traversing a non-returning subroutine means that all unhandled + // exceptions will actually never get sent... + return; + } + // filter exceptions that are locally caught from the innermost enclosing + // try statement to the outermost ones. + if (traversedContext instanceof ExceptionHandlingFlowContext) { + ExceptionHandlingFlowContext exceptionContext = + (ExceptionHandlingFlowContext) traversedContext; + ReferenceBinding[] caughtExceptions; + if ((caughtExceptions = exceptionContext.handledExceptions) != NoExceptions) { + int caughtCount = caughtExceptions.length; + boolean[] locallyCaught = new boolean[raisedCount]; // at most + + for (int caughtIndex = 0; caughtIndex < caughtCount; caughtIndex++) { + ReferenceBinding caughtException = caughtExceptions[caughtIndex]; + for (int raisedIndex = 0; raisedIndex < raisedCount; raisedIndex++) { + TypeBinding raisedException; + if ((raisedException = raisedExceptions[raisedIndex]) != null) { + int state = caughtException == null + ? EqualOrMoreSpecific /* any exception */ + : Scope.compareTypes(raisedException, caughtException); + switch (state) { + case EqualOrMoreSpecific : + exceptionContext.recordHandlingException( + caughtException, + flowInfo.unconditionalInits(), + raisedException, + location, + locallyCaught[raisedIndex]); + // was already definitely caught ? + if (!locallyCaught[raisedIndex]) { + locallyCaught[raisedIndex] = true; + // remember that this exception has been definitely caught + remainingCount--; + } + break; + case MoreGeneric : + exceptionContext.recordHandlingException( + caughtException, + flowInfo.unconditionalInits(), + raisedException, + location, + false); + // was not caught already per construction + } + } + } + } + // remove locally caught exceptions from the remaining ones + for (int i = 0; i < raisedCount; i++) { + if (locallyCaught[i]) { + raisedExceptions[i] = null; // removed from the remaining ones. + } + } + } + // method treatment for unchecked exceptions + if (exceptionContext.isMethodContext) { + for (int i = 0; i < raisedCount; i++) { + TypeBinding raisedException; + if ((raisedException = raisedExceptions[i]) != null) { + if (raisedException.isCompatibleWith(scope.getJavaLangRuntimeException()) + || raisedException.isCompatibleWith(scope.getJavaLangError())) { + remainingCount--; + raisedExceptions[i] = null; + } + } + } + // anonymous constructors are allowed to throw any exceptions (their thrown exceptions + // clause will be fixed up later as per JLS 8.6). + if (exceptionContext.associatedNode instanceof AbstractMethodDeclaration){ + AbstractMethodDeclaration method = (AbstractMethodDeclaration)exceptionContext.associatedNode; + if (method.isConstructor() && method.binding.declaringClass.isAnonymousType()){ + + for (int i = 0; i < raisedCount; i++) { + TypeBinding raisedException; + if ((raisedException = raisedExceptions[i]) != null) { + exceptionContext.mergeUnhandledException(raisedException); + } + } + return; // no need to complain, will fix up constructor exceptions + } + } + break; // not handled anywhere, thus jump to error handling + } + } + if (remainingCount == 0) + return; + + traversedContext.recordReturnFrom(flowInfo.unconditionalInits()); + if (traversedContext.associatedNode instanceof TryStatement){ + flowInfo = flowInfo.copy().addInitializationsFrom(((TryStatement) traversedContext.associatedNode).subRoutineInits); + } + traversedContext = traversedContext.parent; + } + // if reaches this point, then there are some remaining unhandled exception types. + nextReport: for (int i = 0; i < raisedCount; i++) { + TypeBinding exception; + if ((exception = raisedExceptions[i]) != null) { + // only one complaint if same exception declared to be thrown more than once + for (int j = 0; j < i; j++) { + if (raisedExceptions[j] == exception) continue nextReport; // already reported + } + scope.problemReporter().unhandledException(exception, location); + } + } + } + + public void checkExceptionHandlers( + TypeBinding raisedException, + ASTNode location, + FlowInfo flowInfo, + BlockScope scope) { + + // LIGHT-VERSION OF THE EQUIVALENT WITH AN ARRAY OF EXCEPTIONS + // check that all the argument exception types are handled + // JDK Compatible implementation - when an exception type is thrown, + // all related catch blocks are marked as reachable... instead of those only + // until the point where it is safely handled (Smarter - see comment at the end) + FlowContext traversedContext = this; + while (traversedContext != null) { + SubRoutineStatement sub; + if (((sub = traversedContext.subRoutine()) != null) && sub.isSubRoutineEscaping()) { + // traversing a non-returning subroutine means that all unhandled + // exceptions will actually never get sent... + return; + } + + // filter exceptions that are locally caught from the innermost enclosing + // try statement to the outermost ones. + if (traversedContext instanceof ExceptionHandlingFlowContext) { + ExceptionHandlingFlowContext exceptionContext = + (ExceptionHandlingFlowContext) traversedContext; + ReferenceBinding[] caughtExceptions; + if ((caughtExceptions = exceptionContext.handledExceptions) != NoExceptions) { + boolean definitelyCaught = false; + for (int caughtIndex = 0, caughtCount = caughtExceptions.length; + caughtIndex < caughtCount; + caughtIndex++) { + ReferenceBinding caughtException = caughtExceptions[caughtIndex]; + int state = caughtException == null + ? EqualOrMoreSpecific /* any exception */ + : Scope.compareTypes(raisedException, caughtException); + switch (state) { + case EqualOrMoreSpecific : + exceptionContext.recordHandlingException( + caughtException, + flowInfo.unconditionalInits(), + raisedException, + location, + definitelyCaught); + // was it already definitely caught ? + definitelyCaught = true; + break; + case MoreGeneric : + exceptionContext.recordHandlingException( + caughtException, + flowInfo.unconditionalInits(), + raisedException, + location, + false); + // was not caught already per construction + } + } + if (definitelyCaught) + return; + } + // method treatment for unchecked exceptions + if (exceptionContext.isMethodContext) { + if (raisedException.isCompatibleWith(scope.getJavaLangRuntimeException()) + || raisedException.isCompatibleWith(scope.getJavaLangError())) + return; + + // anonymous constructors are allowed to throw any exceptions (their thrown exceptions + // clause will be fixed up later as per JLS 8.6). + if (exceptionContext.associatedNode instanceof AbstractMethodDeclaration){ + AbstractMethodDeclaration method = (AbstractMethodDeclaration)exceptionContext.associatedNode; + if (method.isConstructor() && method.binding.declaringClass.isAnonymousType()){ + + exceptionContext.mergeUnhandledException(raisedException); + return; // no need to complain, will fix up constructor exceptions + } + } + break; // not handled anywhere, thus jump to error handling + } + } + + traversedContext.recordReturnFrom(flowInfo.unconditionalInits()); + if (traversedContext.associatedNode instanceof TryStatement){ + flowInfo = flowInfo.copy().addInitializationsFrom(((TryStatement) traversedContext.associatedNode).subRoutineInits); + } + traversedContext = traversedContext.parent; + } + // if reaches this point, then there are some remaining unhandled exception types. + scope.problemReporter().unhandledException(raisedException, location); + } + + public Label continueLabel() { + + return null; + } + + /* + * lookup through break labels + */ + public FlowContext getTargetContextForBreakLabel(char[] labelName) { + + FlowContext current = this, lastNonReturningSubRoutine = null; + while (current != null) { + if (current.isNonReturningContext()) { + lastNonReturningSubRoutine = current; + } + char[] currentLabelName; + if (((currentLabelName = current.labelName()) != null) + && CharOperation.equals(currentLabelName, labelName)) { + if (lastNonReturningSubRoutine == null) + return current; + return lastNonReturningSubRoutine; + } + current = current.parent; + } + // not found + return null; + } + + /* + * lookup through continue labels + */ + public FlowContext getTargetContextForContinueLabel(char[] labelName) { + + FlowContext current = this; + FlowContext lastContinuable = null; + FlowContext lastNonReturningSubRoutine = null; + + while (current != null) { + if (current.isNonReturningContext()) { + lastNonReturningSubRoutine = current; + } else { + if (current.isContinuable()) { + lastContinuable = current; + } + } + + char[] currentLabelName; + if ((currentLabelName = current.labelName()) != null && CharOperation.equals(currentLabelName, labelName)) { + + // matching label found + if ((lastContinuable != null) + && (current.associatedNode.concreteStatement() == lastContinuable.associatedNode)) { + + if (lastNonReturningSubRoutine == null) return lastContinuable; + return lastNonReturningSubRoutine; + } + // label is found, but not a continuable location + return NotContinuableContext; + } + current = current.parent; + } + // not found + return null; + } + + /* + * lookup a default break through breakable locations + */ + public FlowContext getTargetContextForDefaultBreak() { + + FlowContext current = this, lastNonReturningSubRoutine = null; + while (current != null) { + if (current.isNonReturningContext()) { + lastNonReturningSubRoutine = current; + } + if (current.isBreakable() && current.labelName() == null) { + if (lastNonReturningSubRoutine == null) return current; + return lastNonReturningSubRoutine; + } + current = current.parent; + } + // not found + return null; + } + + /* + * lookup a default continue amongst continuable locations + */ + public FlowContext getTargetContextForDefaultContinue() { + + FlowContext current = this, lastNonReturningSubRoutine = null; + while (current != null) { + if (current.isNonReturningContext()) { + lastNonReturningSubRoutine = current; + } + if (current.isContinuable()) { + if (lastNonReturningSubRoutine == null) + return current; + return lastNonReturningSubRoutine; + } + current = current.parent; + } + // not found + return null; + } + + public String individualToString() { + + return "Flow context"; //$NON-NLS-1$ + } + + public FlowInfo initsOnBreak() { + + return FlowInfo.DEAD_END; + } + + public UnconditionalFlowInfo initsOnReturn() { + + return FlowInfo.DEAD_END; + } + + public boolean isBreakable() { + + return false; + } + + public boolean isContinuable() { + + return false; + } + + public boolean isNonReturningContext() { + + return false; + } + + public boolean isSubRoutine() { + + return false; + } + + public char[] labelName() { + + return null; + } + + public void recordBreakFrom(FlowInfo flowInfo) { + // default implementation: do nothing + } + + public void recordContinueFrom(FlowInfo flowInfo) { + // default implementation: do nothing + } + + boolean recordFinalAssignment( + VariableBinding variable, + Reference finalReference) { + + return true; // keep going + } + + public void recordReturnFrom(FlowInfo flowInfo) { + // default implementation: do nothing + } + + public void recordSettingFinal( + VariableBinding variable, + Reference finalReference, + FlowInfo flowInfo) { + + if (!flowInfo.isReachable()) return; + + // for initialization inside looping statement that effectively loops + FlowContext context = this; + while (context != null) { + if (!context.recordFinalAssignment(variable, finalReference)) { + break; // no need to keep going + } + context = context.parent; + } + } + + void removeFinalAssignmentIfAny(Reference reference) { + // default implementation: do nothing + } + + public SubRoutineStatement subRoutine() { + + return null; + } + + public String toString() { + + StringBuffer buffer = new StringBuffer(); + FlowContext current = this; + int parentsCount = 0; + while ((current = current.parent) != null) { + parentsCount++; + } + FlowContext[] parents = new FlowContext[parentsCount + 1]; + current = this; + int index = parentsCount; + while (index >= 0) { + parents[index--] = current; + current = current.parent; + } + for (int i = 0; i < parentsCount; i++) { + for (int j = 0; j < i; j++) + buffer.append('\t'); + buffer.append(parents[i].individualToString()).append('\n'); + } + buffer.append('*'); + for (int j = 0; j < parentsCount + 1; j++) + buffer.append('\t'); + buffer.append(individualToString()).append('\n'); + return buffer.toString(); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java b/src/java/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java new file mode 100644 index 0000000..1736a5c --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java @@ -0,0 +1,144 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.flow; + +import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; +import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; + +public abstract class FlowInfo { + + public final static int REACHABLE = 0; + public final static int UNREACHABLE = 1; + + public static final UnconditionalFlowInfo DEAD_END; // Represents a dead branch status of initialization + static { + DEAD_END = new UnconditionalFlowInfo(); + DEAD_END.reachMode = UNREACHABLE; + } + abstract public FlowInfo addInitializationsFrom(FlowInfo otherInits); + + abstract public FlowInfo addPotentialInitializationsFrom(FlowInfo otherInits); + + public FlowInfo asNegatedCondition() { + + return this; + } + + public static FlowInfo conditional(FlowInfo initsWhenTrue, FlowInfo initsWhenFalse){ + + // if (initsWhenTrue.equals(initsWhenFalse)) return initsWhenTrue; -- could optimize if #equals is defined + return new ConditionalFlowInfo(initsWhenTrue, initsWhenFalse); + } + + abstract public FlowInfo copy(); + + public static UnconditionalFlowInfo initial(int maxFieldCount) { + UnconditionalFlowInfo info = new UnconditionalFlowInfo(); + info.maxFieldCount = maxFieldCount; + return info; + } + + abstract public FlowInfo initsWhenFalse(); + + abstract public FlowInfo initsWhenTrue(); + + /** + * Check status of definite assignment for a field. + */ + abstract public boolean isDefinitelyAssigned(FieldBinding field); + + /** + * Check status of definite assignment for a local. + */ + public abstract boolean isDefinitelyAssigned(LocalVariableBinding local); + + //abstract public int reachMode(); + + /** + * Check status of potential assignment for a field. + */ + abstract public boolean isPotentiallyAssigned(FieldBinding field); + + /** + * Check status of potential assignment for a local variable. + */ + + abstract public boolean isPotentiallyAssigned(LocalVariableBinding field); + + abstract public boolean isReachable(); + + /** + * Record a field got definitely assigned. + */ + abstract public void markAsDefinitelyAssigned(FieldBinding field); + + /** + * Record a local got definitely assigned. + */ + abstract public void markAsDefinitelyAssigned(LocalVariableBinding local); + + /** + * Clear the initialization info for a field + */ + abstract public void markAsDefinitelyNotAssigned(FieldBinding field); + + /** + * Clear the initialization info for a local variable + */ + abstract public void markAsDefinitelyNotAssigned(LocalVariableBinding local); + + /** + * Merge branches using optimized boolean conditions + */ + public static FlowInfo mergedOptimizedBranches(FlowInfo initsWhenTrue, boolean isOptimizedTrue, FlowInfo initsWhenFalse, boolean isOptimizedFalse, boolean allowFakeDeadBranch) { + FlowInfo mergedInfo; + if (isOptimizedTrue){ + if (initsWhenTrue == FlowInfo.DEAD_END && allowFakeDeadBranch) { + mergedInfo = initsWhenFalse.setReachMode(FlowInfo.UNREACHABLE); + } else { + mergedInfo = initsWhenTrue.addPotentialInitializationsFrom(initsWhenFalse); + } + + } else if (isOptimizedFalse) { + if (initsWhenFalse == FlowInfo.DEAD_END && allowFakeDeadBranch) { + mergedInfo = initsWhenTrue.setReachMode(FlowInfo.UNREACHABLE); + } else { + mergedInfo = initsWhenFalse.addPotentialInitializationsFrom(initsWhenTrue); + } + + } else { + mergedInfo = initsWhenTrue.unconditionalInits().mergedWith(initsWhenFalse.unconditionalInits()); + } + return mergedInfo; + } + + abstract public int reachMode(); + + abstract public FlowInfo setReachMode(int reachMode); + + /** + * Returns the receiver updated in the following way:
    + *
  • intersection of definitely assigned variables, + *
  • union of potentially assigned variables. + *
+ */ + abstract public UnconditionalFlowInfo mergedWith(UnconditionalFlowInfo otherInits); + + public String toString(){ + + if (this == DEAD_END){ + return "FlowInfo.DEAD_END"; //$NON-NLS-1$ + } + return super.toString(); + } + + abstract public UnconditionalFlowInfo unconditionalInits(); +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/flow/InitializationFlowContext.java b/src/java/org/eclipse/jdt/internal/compiler/flow/InitializationFlowContext.java new file mode 100644 index 0000000..e609ae1 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/flow/InitializationFlowContext.java @@ -0,0 +1,97 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.flow; + +import org.eclipse.jdt.internal.compiler.ast.ASTNode; +import org.eclipse.jdt.internal.compiler.lookup.BlockScope; +import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; +import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; + +/** + * Reflects the context of code analysis, keeping track of enclosing + * try statements, exception handlers, etc... + */ +public class InitializationFlowContext extends ExceptionHandlingFlowContext { + + public int exceptionCount; + public TypeBinding[] thrownExceptions = new TypeBinding[5]; + public ASTNode[] exceptionThrowers = new ASTNode[5]; + public FlowInfo[] exceptionThrowerFlowInfos = new FlowInfo[5]; + + public InitializationFlowContext( + FlowContext parent, + ASTNode associatedNode, + BlockScope scope) { + super( + parent, + associatedNode, + NoExceptions, // no exception allowed by default + scope, + FlowInfo.DEAD_END); + } + + public void checkInitializerExceptions( + BlockScope currentScope, + FlowContext initializerContext, + FlowInfo flowInfo) { + for (int i = 0; i < exceptionCount; i++) { + initializerContext.checkExceptionHandlers( + thrownExceptions[i], + exceptionThrowers[i], + exceptionThrowerFlowInfos[i], + currentScope); + } + } + + public String individualToString() { + + StringBuffer buffer = new StringBuffer("Initialization flow context"); //$NON-NLS-1$ + for (int i = 0; i < exceptionCount; i++) { + buffer.append('[').append(thrownExceptions[i].readableName()); + buffer.append('-').append(exceptionThrowerFlowInfos[i].toString()).append(']'); + } + return buffer.toString(); + } + + public void recordHandlingException( + ReferenceBinding exceptionType, + UnconditionalFlowInfo flowInfo, + TypeBinding raisedException, + ASTNode invocationSite, + boolean wasMasked) { + + // even if unreachable code, need to perform unhandled exception diagnosis + int size = thrownExceptions.length; + if (exceptionCount == size) { + System.arraycopy( + thrownExceptions, + 0, + (thrownExceptions = new TypeBinding[size * 2]), + 0, + size); + System.arraycopy( + exceptionThrowers, + 0, + (exceptionThrowers = new ASTNode[size * 2]), + 0, + size); + System.arraycopy( + exceptionThrowerFlowInfos, + 0, + (exceptionThrowerFlowInfos = new FlowInfo[size * 2]), + 0, + size); + } + thrownExceptions[exceptionCount] = raisedException; + exceptionThrowers[exceptionCount] = invocationSite; + exceptionThrowerFlowInfos[exceptionCount++] = flowInfo.copy(); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/flow/InsideSubRoutineFlowContext.java b/src/java/org/eclipse/jdt/internal/compiler/flow/InsideSubRoutineFlowContext.java new file mode 100644 index 0000000..221666b --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/flow/InsideSubRoutineFlowContext.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.flow; + +import org.eclipse.jdt.internal.compiler.ast.ASTNode; +import org.eclipse.jdt.internal.compiler.ast.SubRoutineStatement; + +/** + * Reflects the context of code analysis, keeping track of enclosing + * try statements, exception handlers, etc... + */ +public class InsideSubRoutineFlowContext extends FlowContext { + + public UnconditionalFlowInfo initsOnReturn; + + public InsideSubRoutineFlowContext( + FlowContext parent, + ASTNode associatedNode) { + super(parent, associatedNode); + this.initsOnReturn = FlowInfo.DEAD_END; + } + + public String individualToString() { + + StringBuffer buffer = new StringBuffer("Inside SubRoutine flow context"); //$NON-NLS-1$ + buffer.append("[initsOnReturn -").append(initsOnReturn.toString()).append(']'); //$NON-NLS-1$ + return buffer.toString(); + } + + public UnconditionalFlowInfo initsOnReturn(){ + return this.initsOnReturn; + } + + public boolean isNonReturningContext() { + return subRoutine().isSubRoutineEscaping(); + } + + public SubRoutineStatement subRoutine() { + return (SubRoutineStatement)associatedNode; + } + + public void recordReturnFrom(FlowInfo flowInfo) { + + if (!flowInfo.isReachable()) return; + if (initsOnReturn == FlowInfo.DEAD_END) { + initsOnReturn = flowInfo.copy().unconditionalInits(); + } else { + initsOnReturn = initsOnReturn.mergedWith(flowInfo.copy().unconditionalInits()); + } + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/flow/LabelFlowContext.java b/src/java/org/eclipse/jdt/internal/compiler/flow/LabelFlowContext.java new file mode 100644 index 0000000..0d83e74 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/flow/LabelFlowContext.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.flow; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.ast.ASTNode; +import org.eclipse.jdt.internal.compiler.codegen.Label; +import org.eclipse.jdt.internal.compiler.lookup.BlockScope; + +/** + * Reflects the context of code analysis, keeping track of enclosing + * try statements, exception handlers, etc... + */ +public class LabelFlowContext extends SwitchFlowContext { + + public char[] labelName; + + public LabelFlowContext( + FlowContext parent, + ASTNode associatedNode, + char[] labelName, + Label breakLabel, + BlockScope scope) { + + super(parent, associatedNode, breakLabel); + this.labelName = labelName; + checkLabelValidity(scope); + } + + void checkLabelValidity(BlockScope scope) { + + // check if label was already defined above + FlowContext current = parent; + while (current != null) { + char[] currentLabelName; + if (((currentLabelName = current.labelName()) != null) + && CharOperation.equals(currentLabelName, labelName)) { + scope.problemReporter().alreadyDefinedLabel(labelName, associatedNode); + } + current = current.parent; + } + } + + public String individualToString() { + + return "Label flow context [label:" + String.valueOf(labelName) + "]"; //$NON-NLS-2$ //$NON-NLS-1$ + } + + public char[] labelName() { + + return labelName; + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java b/src/java/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java new file mode 100644 index 0000000..450bdff --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java @@ -0,0 +1,153 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.flow; + +import org.eclipse.jdt.internal.compiler.ast.ASTNode; +import org.eclipse.jdt.internal.compiler.ast.Reference; +import org.eclipse.jdt.internal.compiler.codegen.Label; +import org.eclipse.jdt.internal.compiler.lookup.BlockScope; +import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; +import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; +import org.eclipse.jdt.internal.compiler.lookup.Scope; +import org.eclipse.jdt.internal.compiler.lookup.VariableBinding; + +/** + * Reflects the context of code analysis, keeping track of enclosing + * try statements, exception handlers, etc... + */ +public class LoopingFlowContext extends SwitchFlowContext { + + public Label continueLabel; + public UnconditionalFlowInfo initsOnContinue = FlowInfo.DEAD_END; + Reference finalAssignments[]; + VariableBinding finalVariables[]; + int assignCount = 0; + Scope associatedScope; + + public LoopingFlowContext( + FlowContext parent, + ASTNode associatedNode, + Label breakLabel, + Label continueLabel, + Scope associatedScope) { + super(parent, associatedNode, breakLabel); + this.continueLabel = continueLabel; + this.associatedScope = associatedScope; + } + + public void complainOnFinalAssignmentsInLoop( + BlockScope scope, + FlowInfo flowInfo) { + for (int i = 0; i < assignCount; i++) { + VariableBinding variable = finalVariables[i]; + if (variable == null) continue; + boolean complained = false; // remember if have complained on this final assignment + if (variable instanceof FieldBinding) { + if (flowInfo.isPotentiallyAssigned((FieldBinding) variable)) { + complained = true; + scope.problemReporter().duplicateInitializationOfBlankFinalField( + (FieldBinding) variable, + finalAssignments[i]); + } + } else { + if (flowInfo.isPotentiallyAssigned((LocalVariableBinding) variable)) { + complained = true; + scope.problemReporter().duplicateInitializationOfFinalLocal( + (LocalVariableBinding) variable, + finalAssignments[i]); + } + } + // any reference reported at this level is removed from the parent context where it + // could also be reported again + if (complained) { + FlowContext context = parent; + while (context != null) { + context.removeFinalAssignmentIfAny(finalAssignments[i]); + context = context.parent; + } + } + } + } + + public Label continueLabel() { + return continueLabel; + } + + public String individualToString() { + StringBuffer buffer = new StringBuffer("Looping flow context"); //$NON-NLS-1$ + buffer.append("[initsOnBreak -").append(initsOnBreak.toString()).append(']'); //$NON-NLS-1$ + buffer.append("[initsOnContinue -").append(initsOnContinue.toString()).append(']'); //$NON-NLS-1$ + return buffer.toString(); + } + + public boolean isContinuable() { + return true; + } + + public boolean isContinuedTo() { + return initsOnContinue != FlowInfo.DEAD_END; + } + + public void recordContinueFrom(FlowInfo flowInfo) { + + if (!flowInfo.isReachable()) return; + if (initsOnContinue == FlowInfo.DEAD_END) { + initsOnContinue = flowInfo.copy().unconditionalInits(); + } else { + initsOnContinue = initsOnContinue.mergedWith(flowInfo.copy().unconditionalInits()); + } + } + + boolean recordFinalAssignment( + VariableBinding binding, + Reference finalAssignment) { + + // do not consider variables which are defined inside this loop + if (binding instanceof LocalVariableBinding) { + Scope scope = ((LocalVariableBinding) binding).declaringScope; + while ((scope = scope.parent) != null) { + if (scope == associatedScope) + return false; + } + } + if (assignCount == 0) { + finalAssignments = new Reference[5]; + finalVariables = new VariableBinding[5]; + } else { + if (assignCount == finalAssignments.length) + System.arraycopy( + finalAssignments, + 0, + (finalAssignments = new Reference[assignCount * 2]), + 0, + assignCount); + System.arraycopy( + finalVariables, + 0, + (finalVariables = new VariableBinding[assignCount * 2]), + 0, + assignCount); + } + finalAssignments[assignCount] = finalAssignment; + finalVariables[assignCount++] = binding; + return true; + } + + void removeFinalAssignmentIfAny(Reference reference) { + for (int i = 0; i < assignCount; i++) { + if (finalAssignments[i] == reference) { + finalAssignments[i] = null; + finalVariables[i] = null; + return; + } + } + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/flow/SwitchFlowContext.java b/src/java/org/eclipse/jdt/internal/compiler/flow/SwitchFlowContext.java new file mode 100644 index 0000000..5cd28eb --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/flow/SwitchFlowContext.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.flow; + +import org.eclipse.jdt.internal.compiler.ast.ASTNode; +import org.eclipse.jdt.internal.compiler.codegen.Label; + +/** + * Reflects the context of code analysis, keeping track of enclosing + * try statements, exception handlers, etc... + */ +public class SwitchFlowContext extends FlowContext { + public Label breakLabel; + public UnconditionalFlowInfo initsOnBreak = FlowInfo.DEAD_END; + + public SwitchFlowContext( + FlowContext parent, + ASTNode associatedNode, + Label breakLabel) { + super(parent, associatedNode); + this.breakLabel = breakLabel; + } + + public Label breakLabel() { + return breakLabel; + } + + public String individualToString() { + StringBuffer buffer = new StringBuffer("Switch flow context"); //$NON-NLS-1$ + buffer.append("[initsOnBreak -").append(initsOnBreak.toString()).append(']'); //$NON-NLS-1$ + return buffer.toString(); + } + + public boolean isBreakable() { + return true; + } + + public void recordBreakFrom(FlowInfo flowInfo) { + + if (initsOnBreak == FlowInfo.DEAD_END) { + initsOnBreak = flowInfo.copy().unconditionalInits(); + } else { + initsOnBreak = initsOnBreak.mergedWith(flowInfo.copy().unconditionalInits()); + } + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java b/src/java/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java new file mode 100644 index 0000000..4ae4c52 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java @@ -0,0 +1,559 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.flow; + +import org.eclipse.jdt.internal.compiler.impl.Constant; +import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; +import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; +import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; + +/** + * Record initialization status during definite assignment analysis + * + * No caching of pre-allocated instances. + */ +public class UnconditionalFlowInfo extends FlowInfo { + + + public long definiteInits; + public long potentialInits; + public long extraDefiniteInits[]; + public long extraPotentialInits[]; + + public int reachMode; // by default + + public int maxFieldCount; + + // Constants + public static final int BitCacheSize = 64; // 64 bits in a long. + + UnconditionalFlowInfo() { + this.reachMode = REACHABLE; + } + + // unions of both sets of initialization - used for try/finally + public FlowInfo addInitializationsFrom(FlowInfo inits) { + + if (this == DEAD_END) + return this; + + UnconditionalFlowInfo otherInits = inits.unconditionalInits(); + if (otherInits == DEAD_END) + return this; + + // union of definitely assigned variables, + definiteInits |= otherInits.definiteInits; + // union of potentially set ones + potentialInits |= otherInits.potentialInits; + + // treating extra storage + if (extraDefiniteInits != null) { + if (otherInits.extraDefiniteInits != null) { + // both sides have extra storage + int i = 0, length, otherLength; + if ((length = extraDefiniteInits.length) < (otherLength = otherInits.extraDefiniteInits.length)) { + // current storage is shorter -> grow current (could maybe reuse otherInits extra storage?) + System.arraycopy(extraDefiniteInits, 0, (extraDefiniteInits = new long[otherLength]), 0, length); + System.arraycopy(extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, length); + while (i < length) { + extraDefiniteInits[i] |= otherInits.extraDefiniteInits[i]; + extraPotentialInits[i] |= otherInits.extraPotentialInits[i++]; + } + while (i < otherLength) { + extraPotentialInits[i] = otherInits.extraPotentialInits[i++]; + } + } else { + // current storage is longer + while (i < otherLength) { + extraDefiniteInits[i] |= otherInits.extraDefiniteInits[i]; + extraPotentialInits[i] |= otherInits.extraPotentialInits[i++]; + } + while (i < length) + extraDefiniteInits[i++] = 0; + } + } else { + // no extra storage on otherInits + } + } else + if (otherInits.extraDefiniteInits != null) { + // no storage here, but other has extra storage. + int otherLength; + System.arraycopy(otherInits.extraDefiniteInits, 0, (extraDefiniteInits = new long[otherLength = otherInits.extraDefiniteInits.length]), 0, otherLength); + System.arraycopy(otherInits.extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, otherLength); + } + return this; + } + + // unions of both sets of initialization - used for try/finally + public FlowInfo addPotentialInitializationsFrom(FlowInfo inits) { + + if (this == DEAD_END){ + return this; + } + + UnconditionalFlowInfo otherInits = inits.unconditionalInits(); + if (otherInits == DEAD_END){ + return this; + } + // union of potentially set ones + potentialInits |= otherInits.potentialInits; + + // treating extra storage + if (extraDefiniteInits != null) { + if (otherInits.extraDefiniteInits != null) { + // both sides have extra storage + int i = 0, length, otherLength; + if ((length = extraDefiniteInits.length) < (otherLength = otherInits.extraDefiniteInits.length)) { + // current storage is shorter -> grow current (could maybe reuse otherInits extra storage?) + System.arraycopy(extraDefiniteInits, 0, (extraDefiniteInits = new long[otherLength]), 0, length); + System.arraycopy(extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, length); + while (i < length) { + extraPotentialInits[i] |= otherInits.extraPotentialInits[i++]; + } + while (i < otherLength) { + extraPotentialInits[i] = otherInits.extraPotentialInits[i++]; + } + } else { + // current storage is longer + while (i < otherLength) { + extraPotentialInits[i] |= otherInits.extraPotentialInits[i++]; + } + } + } + } else + if (otherInits.extraDefiniteInits != null) { + // no storage here, but other has extra storage. + int otherLength; + extraDefiniteInits = new long[otherLength = otherInits.extraDefiniteInits.length]; + System.arraycopy(otherInits.extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, otherLength); + } + return this; + } + + /** + * Answers a copy of the current instance + */ + public FlowInfo copy() { + + // do not clone the DeadEnd + if (this == DEAD_END) + return this; + + // look for an unused preallocated object + UnconditionalFlowInfo copy = new UnconditionalFlowInfo(); + + // copy slots + copy.definiteInits = this.definiteInits; + copy.potentialInits = this.potentialInits; + copy.reachMode = this.reachMode; + copy.maxFieldCount = this.maxFieldCount; + + if (this.extraDefiniteInits != null) { + int length; + System.arraycopy(this.extraDefiniteInits, 0, (copy.extraDefiniteInits = new long[ (length = extraDefiniteInits.length)]), 0, length); + System.arraycopy(this.extraPotentialInits, 0, (copy.extraPotentialInits = new long[length]), 0, length); + } + return copy; + } + + public UnconditionalFlowInfo discardFieldInitializations(){ + + int limit = this.maxFieldCount; + + if (limit < BitCacheSize) { + long mask = (1L << limit)-1; + this.definiteInits &= ~mask; + this.potentialInits &= ~mask; + return this; + } + + this.definiteInits = 0; + this.potentialInits = 0; + + // use extra vector + if (extraDefiniteInits == null) { + return this; // if vector not yet allocated, then not initialized + } + int vectorIndex, length = this.extraDefiniteInits.length; + if ((vectorIndex = (limit / BitCacheSize) - 1) >= length) { + return this; // not enough room yet + } + for (int i = 0; i < vectorIndex; i++) { + this.extraDefiniteInits[i] = 0L; + this.extraPotentialInits[i] = 0L; + } + long mask = (1L << (limit % BitCacheSize))-1; + this.extraDefiniteInits[vectorIndex] &= ~mask; + this.extraPotentialInits[vectorIndex] &= ~mask; + return this; + } + + public UnconditionalFlowInfo discardNonFieldInitializations(){ + + int limit = this.maxFieldCount; + + if (limit < BitCacheSize) { + long mask = (1L << limit)-1; + this.definiteInits &= mask; + this.potentialInits &= mask; + return this; + } + // use extra vector + if (extraDefiniteInits == null) { + return this; // if vector not yet allocated, then not initialized + } + int vectorIndex, length = this.extraDefiniteInits.length; + if ((vectorIndex = (limit / BitCacheSize) - 1) >= length) { + return this; // not enough room yet + } + long mask = (1L << (limit % BitCacheSize))-1; + this.extraDefiniteInits[vectorIndex] &= mask; + this.extraPotentialInits[vectorIndex] &= mask; + for (int i = vectorIndex+1; i < length; i++) { + this.extraDefiniteInits[i] = 0L; + this.extraPotentialInits[i] = 0L; + } + return this; + } + + public FlowInfo initsWhenFalse() { + + return this; + } + + public FlowInfo initsWhenTrue() { + + return this; + } + + /** + * Check status of definite assignment at a given position. + * It deals with the dual representation of the InitializationInfo2: + * bits for the first 64 entries, then an array of booleans. + */ + final private boolean isDefinitelyAssigned(int position) { + + // Dependant of CodeStream.isDefinitelyAssigned(..) + // id is zero-based + if (position < BitCacheSize) { + return (definiteInits & (1L << position)) != 0; // use bits + } + // use extra vector + if (extraDefiniteInits == null) + return false; // if vector not yet allocated, then not initialized + int vectorIndex; + if ((vectorIndex = (position / BitCacheSize) - 1) >= extraDefiniteInits.length) + return false; // if not enough room in vector, then not initialized + return ((extraDefiniteInits[vectorIndex]) & (1L << (position % BitCacheSize))) != 0; + } + + /** + * Check status of definite assignment for a field. + */ + final public boolean isDefinitelyAssigned(FieldBinding field) { + + // Dependant of CodeStream.isDefinitelyAssigned(..) + // We do not want to complain in unreachable code + if ((this.reachMode & UNREACHABLE) != 0) + return true; + return isDefinitelyAssigned(field.id); + } + + /** + * Check status of definite assignment for a local. + */ + final public boolean isDefinitelyAssigned(LocalVariableBinding local) { + + // Dependant of CodeStream.isDefinitelyAssigned(..) + // We do not want to complain in unreachable code + if ((this.reachMode & UNREACHABLE) != 0) + return true; + if (local.isArgument) { + return true; + } + // final constants are inlined, and thus considered as always initialized + if (local.constant != Constant.NotAConstant) { + return true; + } + return isDefinitelyAssigned(local.id + maxFieldCount); + } + + public boolean isReachable() { + + return this.reachMode == REACHABLE; + } + + /** + * Check status of potential assignment at a given position. + * It deals with the dual representation of the InitializationInfo3: + * bits for the first 64 entries, then an array of booleans. + */ + final private boolean isPotentiallyAssigned(int position) { + + // id is zero-based + if (position < BitCacheSize) { + // use bits + return (potentialInits & (1L << position)) != 0; + } + // use extra vector + if (extraPotentialInits == null) + return false; // if vector not yet allocated, then not initialized + int vectorIndex; + if ((vectorIndex = (position / BitCacheSize) - 1) >= extraPotentialInits.length) + return false; // if not enough room in vector, then not initialized + return ((extraPotentialInits[vectorIndex]) & (1L << (position % BitCacheSize))) != 0; + } + + /** + * Check status of definite assignment for a field. + */ + final public boolean isPotentiallyAssigned(FieldBinding field) { + + return isPotentiallyAssigned(field.id); + } + + /** + * Check status of potential assignment for a local. + */ + final public boolean isPotentiallyAssigned(LocalVariableBinding local) { + + if (local.isArgument) { + return true; + } + // final constants are inlined, and thus considered as always initialized + if (local.constant != Constant.NotAConstant) { + return true; + } + return isPotentiallyAssigned(local.id + maxFieldCount); + } + + /** + * Record a definite assignment at a given position. + * It deals with the dual representation of the InitializationInfo2: + * bits for the first 64 entries, then an array of booleans. + */ + final private void markAsDefinitelyAssigned(int position) { + + if (this != DEAD_END) { + + // position is zero-based + if (position < BitCacheSize) { + // use bits + long mask; + definiteInits |= (mask = 1L << position); + potentialInits |= mask; + } else { + // use extra vector + int vectorIndex = (position / BitCacheSize) - 1; + if (extraDefiniteInits == null) { + int length; + extraDefiniteInits = new long[length = vectorIndex + 1]; + extraPotentialInits = new long[length]; + } else { + int oldLength; // might need to grow the arrays + if (vectorIndex >= (oldLength = extraDefiniteInits.length)) { + System.arraycopy(extraDefiniteInits, 0, (extraDefiniteInits = new long[vectorIndex + 1]), 0, oldLength); + System.arraycopy(extraPotentialInits, 0, (extraPotentialInits = new long[vectorIndex + 1]), 0, oldLength); + } + } + long mask; + extraDefiniteInits[vectorIndex] |= (mask = 1L << (position % BitCacheSize)); + extraPotentialInits[vectorIndex] |= mask; + } + } + } + + /** + * Record a field got definitely assigned. + */ + public void markAsDefinitelyAssigned(FieldBinding field) { + if (this != DEAD_END) + markAsDefinitelyAssigned(field.id); + } + + /** + * Record a local got definitely assigned. + */ + public void markAsDefinitelyAssigned(LocalVariableBinding local) { + if (this != DEAD_END) + markAsDefinitelyAssigned(local.id + maxFieldCount); + } + + /** + * Clear initialization information at a given position. + * It deals with the dual representation of the InitializationInfo2: + * bits for the first 64 entries, then an array of booleans. + */ + final private void markAsDefinitelyNotAssigned(int position) { + if (this != DEAD_END) { + + // position is zero-based + if (position < BitCacheSize) { + // use bits + long mask; + definiteInits &= ~(mask = 1L << position); + potentialInits &= ~mask; + } else { + // use extra vector + int vectorIndex = (position / BitCacheSize) - 1; + if (extraDefiniteInits == null) { + return; // nothing to do, it was not yet set + } + // might need to grow the arrays + if (vectorIndex >= extraDefiniteInits.length) { + return; // nothing to do, it was not yet set + } + long mask; + extraDefiniteInits[vectorIndex] &= ~(mask = 1L << (position % BitCacheSize)); + extraPotentialInits[vectorIndex] &= ~mask; + } + } + } + + /** + * Clear the initialization info for a field + */ + public void markAsDefinitelyNotAssigned(FieldBinding field) { + + if (this != DEAD_END) + markAsDefinitelyNotAssigned(field.id); + } + + /** + * Clear the initialization info for a local variable + */ + + public void markAsDefinitelyNotAssigned(LocalVariableBinding local) { + + if (this != DEAD_END) + markAsDefinitelyNotAssigned(local.id + maxFieldCount); + } + + /** + * Returns the receiver updated in the following way:
    + *
  • intersection of definitely assigned variables, + *
  • union of potentially assigned variables. + *
+ */ + public UnconditionalFlowInfo mergedWith(UnconditionalFlowInfo otherInits) { + + if (this == DEAD_END) return otherInits; + if (otherInits == DEAD_END) return this; + + if ((this.reachMode & UNREACHABLE) != (otherInits.reachMode & UNREACHABLE)){ + if ((this.reachMode & UNREACHABLE) != 0){ + return otherInits; + } + return this; + } + + // if one branch is not fake reachable, then the merged one is reachable + this.reachMode &= otherInits.reachMode; + + // intersection of definitely assigned variables, + this.definiteInits &= otherInits.definiteInits; + // union of potentially set ones + this.potentialInits |= otherInits.potentialInits; + + // treating extra storage + if (this.extraDefiniteInits != null) { + if (otherInits.extraDefiniteInits != null) { + // both sides have extra storage + int i = 0, length, otherLength; + if ((length = this.extraDefiniteInits.length) < (otherLength = otherInits.extraDefiniteInits.length)) { + // current storage is shorter -> grow current (could maybe reuse otherInits extra storage?) + System.arraycopy(this.extraDefiniteInits, 0, (this.extraDefiniteInits = new long[otherLength]), 0, length); + System.arraycopy(this.extraPotentialInits, 0, (this.extraPotentialInits = new long[otherLength]), 0, length); + while (i < length) { + this.extraDefiniteInits[i] &= otherInits.extraDefiniteInits[i]; + this.extraPotentialInits[i] |= otherInits.extraPotentialInits[i++]; + } + while (i < otherLength) { + this.extraPotentialInits[i] = otherInits.extraPotentialInits[i++]; + } + } else { + // current storage is longer + while (i < otherLength) { + this.extraDefiniteInits[i] &= otherInits.extraDefiniteInits[i]; + this.extraPotentialInits[i] |= otherInits.extraPotentialInits[i++]; + } + while (i < length) + this.extraDefiniteInits[i++] = 0; + } + } else { + // no extra storage on otherInits + int i = 0, length = this.extraDefiniteInits.length; + while (i < length) + this.extraDefiniteInits[i++] = 0; + } + } else + if (otherInits.extraDefiniteInits != null) { + // no storage here, but other has extra storage. + int otherLength; + this.extraDefiniteInits = new long[otherLength = otherInits.extraDefiniteInits.length]; + System.arraycopy(otherInits.extraPotentialInits, 0, (this.extraPotentialInits = new long[otherLength]), 0, otherLength); + } + return this; + } + + /* + * Answer the total number of fields in enclosing types of a given type + */ + static int numberOfEnclosingFields(ReferenceBinding type){ + + int count = 0; + type = type.enclosingType(); + while(type != null) { + count += type.fieldCount(); + type = type.enclosingType(); + } + return count; + } + + public int reachMode(){ + return this.reachMode; + } + + public FlowInfo setReachMode(int reachMode) { + + if (this == DEAD_END) return this; // cannot modify DEAD_END + + // reset optional inits when becoming unreachable + if ((this.reachMode & UNREACHABLE) == 0 && (reachMode & UNREACHABLE) != 0) { + this.potentialInits = 0; + if (this.extraPotentialInits != null){ + for (int i = 0, length = this.extraPotentialInits.length; i < length; i++){ + this.extraPotentialInits[i] = 0; + } + } + } + this.reachMode = reachMode; + + return this; + } + + public String toString(){ + + if (this == DEAD_END){ + return "FlowInfo.DEAD_END"; //$NON-NLS-1$ + } + return "FlowInfo"; //$NON-NLS-1$ + } + + public UnconditionalFlowInfo unconditionalInits() { + + // also see conditional inits, where it requests them to merge + return this; + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/impl/BooleanConstant.java b/src/java/org/eclipse/jdt/internal/compiler/impl/BooleanConstant.java new file mode 100644 index 0000000..e85214f --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/impl/BooleanConstant.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.impl; + +import org.eclipse.jdt.internal.compiler.util.Util; + +public class BooleanConstant extends Constant { + + boolean value; + + public BooleanConstant(boolean value) { + this.value = value; + } + + public boolean booleanValue() { + return value; + } + + public String stringValue() { + //spec 15.17.11 + String s = Util.toBoolean(value).toString(); + if (s == null) return "null"; //$NON-NLS-1$ + return s; + } + + public String toString(){ + return "(boolean)" + value ; //$NON-NLS-1$ + } + + public int typeID() { + return T_boolean; + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/impl/ByteConstant.java b/src/java/org/eclipse/jdt/internal/compiler/impl/ByteConstant.java new file mode 100644 index 0000000..9a5e56a --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/impl/ByteConstant.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.impl; + +public class ByteConstant extends Constant { + byte value; +public ByteConstant(byte value) { + this.value = value; +} +public byte byteValue() { + return this.value; +} +public char charValue() { + return (char) value; +} +public double doubleValue() { + return value; // implicit cast to return type +} +public float floatValue() { + return value; // implicit cast to return type +} +public int intValue() { + return value; // implicit cast to return type +} +public long longValue() { + return value; // implicit cast to return type +} +public short shortValue() { + return value; // implicit cast to return type +} +public String stringValue() { + //spec 15.17.11 + + String s = new Integer(value).toString() ; + if (s == null) return "null"; //$NON-NLS-1$ + return s; +} +public String toString(){ + + return "(byte)" + value ; } //$NON-NLS-1$ +public int typeID() { + return T_byte; +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/impl/CharConstant.java b/src/java/org/eclipse/jdt/internal/compiler/impl/CharConstant.java new file mode 100644 index 0000000..d70f8a3 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/impl/CharConstant.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.impl; + +public class CharConstant extends Constant { + + char value; + + public CharConstant(char value) { + this.value = value; + } + public byte byteValue() { + return (byte) value; + } + public char charValue() { + return this.value; + } + public double doubleValue() { + return value; // implicit cast to return type + } + public float floatValue() { + return value; // implicit cast to return type + } + public int intValue() { + return value; // implicit cast to return type + } + public long longValue() { + return value; // implicit cast to return type + } + public short shortValue() { + return (short) value; + } + public String stringValue() { + //spec 15.17.11 + + String s = new Character(value).toString() ; + if (s == null) return "null"; //$NON-NLS-1$ + return s; + } + public String toString(){ + + return "(char)" + value; //$NON-NLS-1$ + } + public int typeID() { + return T_char; + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java b/src/java/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java new file mode 100644 index 0000000..0d729a4 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java @@ -0,0 +1,695 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.impl; + +import java.io.ByteArrayInputStream; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.Compiler; +import org.eclipse.jdt.internal.compiler.ast.ASTNode; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons; +import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; + +public class CompilerOptions implements ProblemReasons, ProblemSeverities, ClassFileConstants { + + /** + * Option IDs + */ + public static final String OPTION_LocalVariableAttribute = "org.eclipse.jdt.core.compiler.debug.localVariable"; //$NON-NLS-1$ + public static final String OPTION_LineNumberAttribute = "org.eclipse.jdt.core.compiler.debug.lineNumber"; //$NON-NLS-1$ + public static final String OPTION_SourceFileAttribute = "org.eclipse.jdt.core.compiler.debug.sourceFile"; //$NON-NLS-1$ + public static final String OPTION_PreserveUnusedLocal = "org.eclipse.jdt.core.compiler.codegen.unusedLocal"; //$NON-NLS-1$ + public static final String OPTION_DocCommentSupport= "org.eclipse.jdt.core.compiler.doc.comment.support"; //$NON-NLS-1$ + public static final String OPTION_ReportMethodWithConstructorName = "org.eclipse.jdt.core.compiler.problem.methodWithConstructorName"; //$NON-NLS-1$ + public static final String OPTION_ReportOverridingPackageDefaultMethod = "org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod"; //$NON-NLS-1$ + public static final String OPTION_ReportDeprecation = "org.eclipse.jdt.core.compiler.problem.deprecation"; //$NON-NLS-1$ + public static final String OPTION_ReportDeprecationInDeprecatedCode = "org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode"; //$NON-NLS-1$ + public static final String OPTION_ReportDeprecationWhenOverridingDeprecatedMethod = "org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod"; //$NON-NLS-1$ + public static final String OPTION_ReportHiddenCatchBlock = "org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock"; //$NON-NLS-1$ + public static final String OPTION_ReportUnusedLocal = "org.eclipse.jdt.core.compiler.problem.unusedLocal"; //$NON-NLS-1$ + public static final String OPTION_ReportUnusedParameter = "org.eclipse.jdt.core.compiler.problem.unusedParameter"; //$NON-NLS-1$ + public static final String OPTION_ReportUnusedParameterWhenImplementingAbstract = "org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract"; //$NON-NLS-1$ + public static final String OPTION_ReportUnusedParameterWhenOverridingConcrete = "org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete"; //$NON-NLS-1$ + public static final String OPTION_ReportUnusedImport = "org.eclipse.jdt.core.compiler.problem.unusedImport"; //$NON-NLS-1$ + public static final String OPTION_ReportSyntheticAccessEmulation = "org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation"; //$NON-NLS-1$ + public static final String OPTION_ReportNoEffectAssignment = "org.eclipse.jdt.core.compiler.problem.noEffectAssignment"; //$NON-NLS-1$ + public static final String OPTION_ReportLocalVariableHiding = "org.eclipse.jdt.core.compiler.problem.localVariableHiding"; //$NON-NLS-1$ + public static final String OPTION_ReportSpecialParameterHidingField = "org.eclipse.jdt.core.compiler.problem.specialParameterHidingField"; //$NON-NLS-1$ + public static final String OPTION_ReportFieldHiding = "org.eclipse.jdt.core.compiler.problem.fieldHiding"; //$NON-NLS-1$ + public static final String OPTION_ReportPossibleAccidentalBooleanAssignment = "org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment"; //$NON-NLS-1$ + public static final String OPTION_ReportNonExternalizedStringLiteral = "org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral"; //$NON-NLS-1$ + public static final String OPTION_ReportIncompatibleNonInheritedInterfaceMethod = "org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod"; //$NON-NLS-1$ + public static final String OPTION_ReportUnusedPrivateMember = "org.eclipse.jdt.core.compiler.problem.unusedPrivateMember"; //$NON-NLS-1$ + public static final String OPTION_ReportNoImplicitStringConversion = "org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion"; //$NON-NLS-1$ + public static final String OPTION_ReportAssertIdentifier = "org.eclipse.jdt.core.compiler.problem.assertIdentifier"; //$NON-NLS-1$ + public static final String OPTION_ReportNonStaticAccessToStatic = "org.eclipse.jdt.core.compiler.problem.staticAccessReceiver"; //$NON-NLS-1$ + public static final String OPTION_ReportIndirectStaticAccess = "org.eclipse.jdt.core.compiler.problem.indirectStaticAccess"; //$NON-NLS-1$ + public static final String OPTION_ReportEmptyStatement = "org.eclipse.jdt.core.compiler.problem.emptyStatement"; //$NON-NLS-1$ + public static final String OPTION_ReportUnnecessaryTypeCheck = "org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck"; //$NON-NLS-1$ + public static final String OPTION_ReportUnnecessaryElse = "org.eclipse.jdt.core.compiler.problem.unnecessaryElse"; //$NON-NLS-1$ + public static final String OPTION_ReportUndocumentedEmptyBlock = "org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock"; //$NON-NLS-1$ + public static final String OPTION_ReportInvalidJavadoc = "org.eclipse.jdt.core.compiler.problem.invalidJavadoc"; //$NON-NLS-1$ + public static final String OPTION_ReportInvalidJavadocTags = "org.eclipse.jdt.core.compiler.problem.invalidJavadocTags"; //$NON-NLS-1$ + public static final String OPTION_ReportInvalidJavadocTagsVisibility = "org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility"; //$NON-NLS-1$ + public static final String OPTION_ReportMissingJavadocTags = "org.eclipse.jdt.core.compiler.problem.missingJavadocTags"; //$NON-NLS-1$ + public static final String OPTION_ReportMissingJavadocTagsVisibility = "org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility"; //$NON-NLS-1$ + public static final String OPTION_ReportMissingJavadocTagsOverriding = "org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding"; //$NON-NLS-1$ + public static final String OPTION_ReportMissingJavadocComments = "org.eclipse.jdt.core.compiler.problem.missingJavadocComments"; //$NON-NLS-1$ + public static final String OPTION_ReportMissingJavadocCommentsVisibility = "org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility"; //$NON-NLS-1$ + public static final String OPTION_ReportMissingJavadocCommentsOverriding = "org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding"; //$NON-NLS-1$ + public static final String OPTION_ReportFinallyBlockNotCompletingNormally = "org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally"; //$NON-NLS-1$ + public static final String OPTION_ReportUnusedDeclaredThrownException = "org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException"; //$NON-NLS-1$ + public static final String OPTION_ReportUnusedDeclaredThrownExceptionWhenOverriding = "org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding"; //$NON-NLS-1$ + public static final String OPTION_ReportUnqualifiedFieldAccess = "org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess"; //$NON-NLS-1$ + public static final String OPTION_Source = "org.eclipse.jdt.core.compiler.source"; //$NON-NLS-1$ + public static final String OPTION_TargetPlatform = "org.eclipse.jdt.core.compiler.codegen.targetPlatform"; //$NON-NLS-1$ + public static final String OPTION_Compliance = "org.eclipse.jdt.core.compiler.compliance"; //$NON-NLS-1$ + public static final String OPTION_Encoding = "org.eclipse.jdt.core.encoding"; //$NON-NLS-1$ + public static final String OPTION_MaxProblemPerUnit = "org.eclipse.jdt.core.compiler.maxProblemPerUnit"; //$NON-NLS-1$ + public static final String OPTION_TaskTags = "org.eclipse.jdt.core.compiler.taskTags"; //$NON-NLS-1$ + public static final String OPTION_TaskPriorities = "org.eclipse.jdt.core.compiler.taskPriorities"; //$NON-NLS-1$ + public static final String OPTION_TaskCaseSensitive = "org.eclipse.jdt.core.compiler.taskCaseSensitive"; //$NON-NLS-1$ + public static final String OPTION_InlineJsr = "org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode"; //$NON-NLS-1$ + + // Backward compatibility + public static final String OPTION_ReportInvalidAnnotation = "org.eclipse.jdt.core.compiler.problem.invalidAnnotation"; //$NON-NLS-1$ + public static final String OPTION_ReportMissingAnnotation = "org.eclipse.jdt.core.compiler.problem.missingAnnotation"; //$NON-NLS-1$ + public static final String OPTION_ReportMissingJavadoc = "org.eclipse.jdt.core.compiler.problem.missingJavadoc"; //$NON-NLS-1$ + + /* should surface ??? */ + public static final String OPTION_PrivateConstructorAccess = "org.eclipse.jdt.core.compiler.codegen.constructorAccessEmulation"; //$NON-NLS-1$ + + /** + * Possible values for configurable options + */ + public static final String GENERATE = "generate";//$NON-NLS-1$ + public static final String DO_NOT_GENERATE = "do not generate"; //$NON-NLS-1$ + public static final String PRESERVE = "preserve"; //$NON-NLS-1$ + public static final String OPTIMIZE_OUT = "optimize out"; //$NON-NLS-1$ + public static final String VERSION_1_1 = "1.1"; //$NON-NLS-1$ + public static final String VERSION_1_2 = "1.2"; //$NON-NLS-1$ + public static final String VERSION_1_3 = "1.3"; //$NON-NLS-1$ + public static final String VERSION_1_4 = "1.4"; //$NON-NLS-1$ + public static final String VERSION_1_5 = "1.5"; //$NON-NLS-1$ + public static final String ERROR = "error"; //$NON-NLS-1$ + public static final String WARNING = "warning"; //$NON-NLS-1$ + public static final String IGNORE = "ignore"; //$NON-NLS-1$ + public static final String ENABLED = "enabled"; //$NON-NLS-1$ + public static final String DISABLED = "disabled"; //$NON-NLS-1$ + public static final String PUBLIC = "public"; //$NON-NLS-1$ + public static final String PROTECTED = "protected"; //$NON-NLS-1$ + public static final String DEFAULT = "default"; //$NON-NLS-1$ + public static final String PRIVATE = "private"; //$NON-NLS-1$ + + /** + * Bit mask for configurable problems (error/warning threshold) + */ + public static final long MethodWithConstructorName = ASTNode.Bit1; + public static final long OverriddenPackageDefaultMethod = ASTNode.Bit2; + public static final long UsingDeprecatedAPI = ASTNode.Bit3; + public static final long MaskedCatchBlock = ASTNode.Bit4; + public static final long UnusedLocalVariable = ASTNode.Bit5; + public static final long UnusedArgument = ASTNode.Bit6; + public static final long NoImplicitStringConversion = ASTNode.Bit7; + public static final long AccessEmulation = ASTNode.Bit8; + public static final long NonExternalizedString = ASTNode.Bit9; + public static final long AssertUsedAsAnIdentifier = ASTNode.Bit10; + public static final long UnusedImport = ASTNode.Bit11; + public static final long NonStaticAccessToStatic = ASTNode.Bit12; + public static final long Task = ASTNode.Bit13; + public static final long NoEffectAssignment = ASTNode.Bit14; + public static final long IncompatibleNonInheritedInterfaceMethod = ASTNode.Bit15; + public static final long UnusedPrivateMember = ASTNode.Bit16; + public static final long LocalVariableHiding = ASTNode.Bit17; + public static final long FieldHiding = ASTNode.Bit18; + public static final long AccidentalBooleanAssign = ASTNode.Bit19; + public static final long EmptyStatement = ASTNode.Bit20; + public static final long MissingJavadocComments = ASTNode.Bit21; + public static final long MissingJavadocTags = ASTNode.Bit22; + public static final long UnqualifiedFieldAccess = ASTNode.Bit23; + public static final long UnusedDeclaredThrownException = ASTNode.Bit24; + public static final long FinallyBlockNotCompleting = ASTNode.Bit25; + public static final long InvalidJavadoc = ASTNode.Bit26; + public static final long UnnecessaryTypeCheck = ASTNode.Bit27; + public static final long UndocumentedEmptyBlock = ASTNode.Bit28; + public static final long IndirectStaticAccess = ASTNode.Bit29; + public static final long UnnecessaryElse = ASTNode.Bit30; + + // Default severity level for handlers + public long errorThreshold = 0; + + public long warningThreshold = + MethodWithConstructorName + | UsingDeprecatedAPI + | MaskedCatchBlock + | OverriddenPackageDefaultMethod + | UnusedImport + | NonStaticAccessToStatic + | NoEffectAssignment + | IncompatibleNonInheritedInterfaceMethod + | NoImplicitStringConversion + | FinallyBlockNotCompleting + | AssertUsedAsAnIdentifier; + + // Debug attributes + public static final int Source = 1; // SourceFileAttribute + public static final int Lines = 2; // LineNumberAttribute + public static final int Vars = 4; // LocalVariableTableAttribute + + // By default only lines and source attributes are generated. + public int produceDebugAttributes = Lines | Source; + + public long complianceLevel = JDK1_4; // by default be compliant with 1.4 + public long sourceLevel = JDK1_3; //1.3 source behavior by default + public long targetJDK = JDK1_2; // default generates for JVM1.2 + + // toggle private access emulation for 1.2 (constr. accessor has extra arg on constructor) or 1.3 (make private constructor default access when access needed) + public boolean isPrivateConstructorAccessChangingVisibility = false; // by default, follows 1.2 + + // source encoding format + public String defaultEncoding = null; // will use the platform default encoding + + // print what unit is being processed + public boolean verbose = Compiler.DEBUG; + + // indicates if reference info is desired + public boolean produceReferenceInfo = false; + + // indicates if unused/optimizable local variables need to be preserved (debugging purpose) + public boolean preserveAllLocalVariables = false; + + // indicates whether literal expressions are inlined at parse-time or not + public boolean parseLiteralExpressionsAsConstants = true; + + // max problems per compilation unit + public int maxProblemsPerUnit = 100; // no more than 100 problems per default + + // tags used to recognize tasks in comments + public char[][] taskTags = null; + public char[][] taskPriorites = null; + public boolean isTaskCaseSensitive = true; + + // deprecation report + public boolean reportDeprecationInsideDeprecatedCode = false; + public boolean reportDeprecationWhenOverridingDeprecatedMethod = false; + + // unused parameters report + public boolean reportUnusedParameterWhenImplementingAbstract = false; + public boolean reportUnusedParameterWhenOverridingConcrete = false; + + // unused declaration of thrown exception + public boolean reportUnusedDeclaredThrownExceptionWhenOverriding = false; + + // constructor/setter parameter hiding + public boolean reportSpecialParameterHidingField = false; + + // check javadoc comments + public int reportInvalidJavadocTagsVisibility = AccPrivate; + public boolean reportInvalidJavadocTags = true; + + // check missing javadoc tags + public int reportMissingJavadocTagsVisibility = AccPrivate; + public boolean reportMissingJavadocTagsOverriding = true; + + // check missing javadoc comments + public int reportMissingJavadocCommentsVisibility = AccPublic; + public boolean reportMissingJavadocCommentsOverriding = true; + + // JSR bytecode inlining + public boolean inlineJsrBytecode = false; + + // javadoc comment support + public boolean docCommentSupport = false; + + + /** + * Initializing the compiler options with defaults + */ + public CompilerOptions(){ + // use default options + } + + /** + * Initializing the compiler options with external settings + * @param settings + */ + public CompilerOptions(Map settings){ + + if (settings == null) return; + set(settings); + } + + public Map getMap() { + Map optionsMap = new HashMap(30); + optionsMap.put(OPTION_LocalVariableAttribute, (this.produceDebugAttributes & Vars) != 0 ? GENERATE : DO_NOT_GENERATE); + optionsMap.put(OPTION_LineNumberAttribute, (this.produceDebugAttributes & Lines) != 0 ? GENERATE : DO_NOT_GENERATE); + optionsMap.put(OPTION_SourceFileAttribute, (this.produceDebugAttributes & Source) != 0 ? GENERATE : DO_NOT_GENERATE); + optionsMap.put(OPTION_PreserveUnusedLocal, this.preserveAllLocalVariables ? PRESERVE : OPTIMIZE_OUT); + optionsMap.put(OPTION_DocCommentSupport, this.docCommentSupport ? ENABLED : DISABLED); + optionsMap.put(OPTION_ReportMethodWithConstructorName, getSeverityString(MethodWithConstructorName)); + optionsMap.put(OPTION_ReportOverridingPackageDefaultMethod, getSeverityString(OverriddenPackageDefaultMethod)); + optionsMap.put(OPTION_ReportDeprecation, getSeverityString(UsingDeprecatedAPI)); + optionsMap.put(OPTION_ReportDeprecationInDeprecatedCode, this.reportDeprecationInsideDeprecatedCode ? ENABLED : DISABLED); + optionsMap.put(OPTION_ReportDeprecationWhenOverridingDeprecatedMethod, this.reportDeprecationWhenOverridingDeprecatedMethod ? ENABLED : DISABLED); + optionsMap.put(OPTION_ReportHiddenCatchBlock, getSeverityString(MaskedCatchBlock)); + optionsMap.put(OPTION_ReportUnusedLocal, getSeverityString(UnusedLocalVariable)); + optionsMap.put(OPTION_ReportUnusedParameter, getSeverityString(UnusedArgument)); + optionsMap.put(OPTION_ReportUnusedImport, getSeverityString(UnusedImport)); + optionsMap.put(OPTION_ReportSyntheticAccessEmulation, getSeverityString(AccessEmulation)); + optionsMap.put(OPTION_ReportNoEffectAssignment, getSeverityString(NoEffectAssignment)); + optionsMap.put(OPTION_ReportNonExternalizedStringLiteral, getSeverityString(NonExternalizedString)); + optionsMap.put(OPTION_ReportNoImplicitStringConversion, getSeverityString(NoImplicitStringConversion)); + optionsMap.put(OPTION_ReportNonStaticAccessToStatic, getSeverityString(NonStaticAccessToStatic)); + optionsMap.put(OPTION_ReportIndirectStaticAccess, getSeverityString(IndirectStaticAccess)); + optionsMap.put(OPTION_ReportIncompatibleNonInheritedInterfaceMethod, getSeverityString(IncompatibleNonInheritedInterfaceMethod)); + optionsMap.put(OPTION_ReportUnusedPrivateMember, getSeverityString(UnusedPrivateMember)); + optionsMap.put(OPTION_ReportLocalVariableHiding, getSeverityString(LocalVariableHiding)); + optionsMap.put(OPTION_ReportFieldHiding, getSeverityString(FieldHiding)); + optionsMap.put(OPTION_ReportPossibleAccidentalBooleanAssignment, getSeverityString(AccidentalBooleanAssign)); + optionsMap.put(OPTION_ReportEmptyStatement, getSeverityString(EmptyStatement)); + optionsMap.put(OPTION_ReportAssertIdentifier, getSeverityString(AssertUsedAsAnIdentifier)); + optionsMap.put(OPTION_ReportUndocumentedEmptyBlock, getSeverityString(UndocumentedEmptyBlock)); + optionsMap.put(OPTION_ReportUnnecessaryTypeCheck, getSeverityString(UnnecessaryTypeCheck)); + optionsMap.put(OPTION_ReportUnnecessaryElse, getSeverityString(UnnecessaryElse)); + optionsMap.put(OPTION_ReportInvalidJavadoc, getSeverityString(InvalidJavadoc)); + optionsMap.put(OPTION_ReportInvalidJavadocTagsVisibility, getVisibilityString(this.reportInvalidJavadocTagsVisibility)); + optionsMap.put(OPTION_ReportInvalidJavadocTags, this.reportInvalidJavadocTags? ENABLED : DISABLED); + optionsMap.put(OPTION_ReportMissingJavadocTags, getSeverityString(MissingJavadocTags)); + optionsMap.put(OPTION_ReportMissingJavadocTagsVisibility, getVisibilityString(this.reportMissingJavadocTagsVisibility)); + optionsMap.put(OPTION_ReportMissingJavadocTagsOverriding, this.reportMissingJavadocTagsOverriding ? ENABLED : DISABLED); + optionsMap.put(OPTION_ReportMissingJavadocComments, getSeverityString(MissingJavadocComments)); + optionsMap.put(OPTION_ReportMissingJavadocCommentsVisibility, getVisibilityString(this.reportMissingJavadocCommentsVisibility)); + optionsMap.put(OPTION_ReportMissingJavadocCommentsOverriding, this.reportMissingJavadocCommentsOverriding ? ENABLED : DISABLED); + optionsMap.put(OPTION_ReportFinallyBlockNotCompletingNormally, getSeverityString(FinallyBlockNotCompleting)); + optionsMap.put(OPTION_ReportUnusedDeclaredThrownException, getSeverityString(UnusedDeclaredThrownException)); + optionsMap.put(OPTION_ReportUnusedDeclaredThrownExceptionWhenOverriding, this.reportUnusedDeclaredThrownExceptionWhenOverriding ? ENABLED : DISABLED); + optionsMap.put(OPTION_ReportUnqualifiedFieldAccess, getSeverityString(UnqualifiedFieldAccess)); + optionsMap.put(OPTION_Compliance, versionFromJdkLevel(this.complianceLevel)); + optionsMap.put(OPTION_Source, versionFromJdkLevel(this.sourceLevel)); + optionsMap.put(OPTION_TargetPlatform, versionFromJdkLevel(this.targetJDK)); + if (this.defaultEncoding != null) { + optionsMap.put(OPTION_Encoding, this.defaultEncoding); + } + optionsMap.put(OPTION_TaskTags, this.taskTags == null ? "" : new String(CharOperation.concatWith(this.taskTags,','))); //$NON-NLS-1$ + optionsMap.put(OPTION_TaskPriorities, this.taskPriorites == null ? "" : new String(CharOperation.concatWith(this.taskPriorites,','))); //$NON-NLS-1$ + optionsMap.put(OPTION_TaskCaseSensitive, this.isTaskCaseSensitive ? ENABLED : DISABLED); + optionsMap.put(OPTION_ReportUnusedParameterWhenImplementingAbstract, this.reportUnusedParameterWhenImplementingAbstract ? ENABLED : DISABLED); + optionsMap.put(OPTION_ReportUnusedParameterWhenOverridingConcrete, this.reportUnusedParameterWhenOverridingConcrete ? ENABLED : DISABLED); + optionsMap.put(OPTION_ReportSpecialParameterHidingField, this.reportSpecialParameterHidingField ? ENABLED : DISABLED); + optionsMap.put(OPTION_MaxProblemPerUnit, String.valueOf(this.maxProblemsPerUnit)); + optionsMap.put(OPTION_InlineJsr, this.inlineJsrBytecode ? ENABLED : DISABLED); + return optionsMap; + } + + public int getSeverity(long irritant) { + if((this.warningThreshold & irritant) != 0) + return Warning; + if((this.errorThreshold & irritant) != 0) + return Error; + return Ignore; + } + + public String getSeverityString(long irritant) { + if((this.warningThreshold & irritant) != 0) + return WARNING; + if((this.errorThreshold & irritant) != 0) + return ERROR; + return IGNORE; + } + + public String getVisibilityString(int level) { + switch (level) { + case AccPublic: + return PUBLIC; + case AccProtected: + return PROTECTED; + case AccPrivate: + return PRIVATE; + default: + return DEFAULT; + } + } + + public void set(Map optionsMap) { + + Object optionValue; + if ((optionValue = optionsMap.get(OPTION_LocalVariableAttribute)) != null) { + if (GENERATE.equals(optionValue)) { + this.produceDebugAttributes |= Vars; + } else if (DO_NOT_GENERATE.equals(optionValue)) { + this.produceDebugAttributes &= ~Vars; + } + } + if ((optionValue = optionsMap.get(OPTION_LineNumberAttribute)) != null) { + if (GENERATE.equals(optionValue)) { + this.produceDebugAttributes |= Lines; + } else if (DO_NOT_GENERATE.equals(optionValue)) { + this.produceDebugAttributes &= ~Lines; + } + } + if ((optionValue = optionsMap.get(OPTION_SourceFileAttribute)) != null) { + if (GENERATE.equals(optionValue)) { + this.produceDebugAttributes |= Source; + } else if (DO_NOT_GENERATE.equals(optionValue)) { + this.produceDebugAttributes &= ~Source; + } + } + if ((optionValue = optionsMap.get(OPTION_PreserveUnusedLocal)) != null) { + if (PRESERVE.equals(optionValue)) { + this.preserveAllLocalVariables = true; + } else if (OPTIMIZE_OUT.equals(optionValue)) { + this.preserveAllLocalVariables = false; + } + } + if ((optionValue = optionsMap.get(OPTION_ReportDeprecationInDeprecatedCode)) != null) { + if (ENABLED.equals(optionValue)) { + this.reportDeprecationInsideDeprecatedCode = true; + } else if (DISABLED.equals(optionValue)) { + this.reportDeprecationInsideDeprecatedCode = false; + } + } + if ((optionValue = optionsMap.get(OPTION_ReportDeprecationWhenOverridingDeprecatedMethod)) != null) { + if (ENABLED.equals(optionValue)) { + this.reportDeprecationWhenOverridingDeprecatedMethod = true; + } else if (DISABLED.equals(optionValue)) { + this.reportDeprecationWhenOverridingDeprecatedMethod = false; + } + } + if ((optionValue = optionsMap.get(OPTION_ReportUnusedDeclaredThrownExceptionWhenOverriding)) != null) { + if (ENABLED.equals(optionValue)) { + this.reportUnusedDeclaredThrownExceptionWhenOverriding = true; + } else if (DISABLED.equals(optionValue)) { + this.reportUnusedDeclaredThrownExceptionWhenOverriding = false; + } + } + if ((optionValue = optionsMap.get(OPTION_Compliance)) != null) { + long level = versionToJdkLevel(optionValue); + if (level != 0) this.complianceLevel = level; + } + if ((optionValue = optionsMap.get(OPTION_Source)) != null) { + long level = versionToJdkLevel(optionValue); + if (level != 0) this.sourceLevel = level; + } + if ((optionValue = optionsMap.get(OPTION_TargetPlatform)) != null) { + long level = versionToJdkLevel(optionValue); + if (level != 0) this.targetJDK = level; + } + if ((optionValue = optionsMap.get(OPTION_Encoding)) != null) { + if (optionValue instanceof String) { + this.defaultEncoding = null; + String stringValue = (String) optionValue; + if (stringValue.length() > 0){ + try { + new InputStreamReader(new ByteArrayInputStream(new byte[0]), stringValue); + this.defaultEncoding = stringValue; + } catch(UnsupportedEncodingException e){ + // ignore unsupported encoding + } + } + } + } + if ((optionValue = optionsMap.get(OPTION_PrivateConstructorAccess)) != null) { + long level = versionToJdkLevel(optionValue); + if (level >= JDK1_3) this.isPrivateConstructorAccessChangingVisibility = true; + } + if ((optionValue = optionsMap.get(OPTION_ReportUnusedParameterWhenImplementingAbstract)) != null) { + if (ENABLED.equals(optionValue)) { + this.reportUnusedParameterWhenImplementingAbstract = true; + } else if (DISABLED.equals(optionValue)) { + this.reportUnusedParameterWhenImplementingAbstract = false; + } + } + if ((optionValue = optionsMap.get(OPTION_ReportUnusedParameterWhenOverridingConcrete)) != null) { + if (ENABLED.equals(optionValue)) { + this.reportUnusedParameterWhenOverridingConcrete = true; + } else if (DISABLED.equals(optionValue)) { + this.reportUnusedParameterWhenOverridingConcrete = false; + } + } + if ((optionValue = optionsMap.get(OPTION_ReportSpecialParameterHidingField)) != null) { + if (ENABLED.equals(optionValue)) { + this.reportSpecialParameterHidingField = true; + } else if (DISABLED.equals(optionValue)) { + this.reportSpecialParameterHidingField = false; + } + } + if ((optionValue = optionsMap.get(OPTION_MaxProblemPerUnit)) != null) { + if (optionValue instanceof String) { + String stringValue = (String) optionValue; + try { + int val = Integer.parseInt(stringValue); + if (val >= 0) this.maxProblemsPerUnit = val; + } catch(NumberFormatException e){ + // ignore ill-formatted limit + } + } + } + if ((optionValue = optionsMap.get(OPTION_TaskTags)) != null) { + if (optionValue instanceof String) { + String stringValue = (String) optionValue; + if (stringValue.length() == 0) { + this.taskTags = null; + } else { + this.taskTags = CharOperation.splitAndTrimOn(',', stringValue.toCharArray()); + } + } + } + if ((optionValue = optionsMap.get(OPTION_TaskPriorities)) != null) { + if (optionValue instanceof String) { + String stringValue = (String) optionValue; + if (stringValue.length() == 0) { + this.taskPriorites = null; + } else { + this.taskPriorites = CharOperation.splitAndTrimOn(',', stringValue.toCharArray()); + } + } + } + if ((optionValue = optionsMap.get(OPTION_TaskCaseSensitive)) != null) { + if (ENABLED.equals(optionValue)) { + this.isTaskCaseSensitive = true; + } else if (DISABLED.equals(optionValue)) { + this.isTaskCaseSensitive = false; + } + } + if ((optionValue = optionsMap.get(OPTION_InlineJsr)) != null) { + if (ENABLED.equals(optionValue)) { + this.inlineJsrBytecode = true; + } else if (DISABLED.equals(optionValue)) { + this.inlineJsrBytecode = false; + } + } + if ((optionValue = optionsMap.get(OPTION_ReportMethodWithConstructorName)) != null) updateSeverity(MethodWithConstructorName, optionValue); + if ((optionValue = optionsMap.get(OPTION_ReportOverridingPackageDefaultMethod)) != null) updateSeverity(OverriddenPackageDefaultMethod, optionValue); + if ((optionValue = optionsMap.get(OPTION_ReportDeprecation)) != null) updateSeverity(UsingDeprecatedAPI, optionValue); + if ((optionValue = optionsMap.get(OPTION_ReportHiddenCatchBlock)) != null) updateSeverity(MaskedCatchBlock, optionValue); + if ((optionValue = optionsMap.get(OPTION_ReportUnusedLocal)) != null) updateSeverity(UnusedLocalVariable, optionValue); + if ((optionValue = optionsMap.get(OPTION_ReportUnusedParameter)) != null) updateSeverity(UnusedArgument, optionValue); + if ((optionValue = optionsMap.get(OPTION_ReportUnusedImport)) != null) updateSeverity(UnusedImport, optionValue); + if ((optionValue = optionsMap.get(OPTION_ReportUnusedPrivateMember)) != null) updateSeverity(UnusedPrivateMember, optionValue); + if ((optionValue = optionsMap.get(OPTION_ReportUnusedDeclaredThrownException)) != null) updateSeverity(UnusedDeclaredThrownException, optionValue); + if ((optionValue = optionsMap.get(OPTION_ReportNoImplicitStringConversion)) != null) updateSeverity(NoImplicitStringConversion, optionValue); + if ((optionValue = optionsMap.get(OPTION_ReportSyntheticAccessEmulation)) != null) updateSeverity(AccessEmulation, optionValue); + if ((optionValue = optionsMap.get(OPTION_ReportLocalVariableHiding)) != null) updateSeverity(LocalVariableHiding, optionValue); + if ((optionValue = optionsMap.get(OPTION_ReportFieldHiding)) != null) updateSeverity(FieldHiding, optionValue); + if ((optionValue = optionsMap.get(OPTION_ReportPossibleAccidentalBooleanAssignment)) != null) updateSeverity(AccidentalBooleanAssign, optionValue); + if ((optionValue = optionsMap.get(OPTION_ReportEmptyStatement)) != null) updateSeverity(EmptyStatement, optionValue); + if ((optionValue = optionsMap.get(OPTION_ReportNonExternalizedStringLiteral)) != null) updateSeverity(NonExternalizedString, optionValue); + if ((optionValue = optionsMap.get(OPTION_ReportAssertIdentifier)) != null) updateSeverity(AssertUsedAsAnIdentifier, optionValue); + if ((optionValue = optionsMap.get(OPTION_ReportNonStaticAccessToStatic)) != null) updateSeverity(NonStaticAccessToStatic, optionValue); + if ((optionValue = optionsMap.get(OPTION_ReportIndirectStaticAccess)) != null) updateSeverity(IndirectStaticAccess, optionValue); + if ((optionValue = optionsMap.get(OPTION_ReportIncompatibleNonInheritedInterfaceMethod)) != null) updateSeverity(IncompatibleNonInheritedInterfaceMethod, optionValue); + if ((optionValue = optionsMap.get(OPTION_ReportUndocumentedEmptyBlock)) != null) updateSeverity(UndocumentedEmptyBlock, optionValue); + if ((optionValue = optionsMap.get(OPTION_ReportUnnecessaryTypeCheck)) != null) updateSeverity(UnnecessaryTypeCheck, optionValue); + if ((optionValue = optionsMap.get(OPTION_ReportFinallyBlockNotCompletingNormally)) != null) updateSeverity(FinallyBlockNotCompleting, optionValue); + if ((optionValue = optionsMap.get(OPTION_ReportUnqualifiedFieldAccess)) != null) updateSeverity(UnqualifiedFieldAccess, optionValue); + if ((optionValue = optionsMap.get(OPTION_ReportNoEffectAssignment)) != null) updateSeverity(NoEffectAssignment, optionValue); + if ((optionValue = optionsMap.get(OPTION_ReportUnnecessaryElse)) != null) updateSeverity(UnnecessaryElse, optionValue); + + // Javadoc options + if ((optionValue = optionsMap.get(OPTION_DocCommentSupport)) != null) { + if (ENABLED.equals(optionValue)) { + this.docCommentSupport = true; + } else if (DISABLED.equals(optionValue)) { + this.docCommentSupport = false; + } + } + if ((optionValue = optionsMap.get(OPTION_ReportInvalidJavadoc)) != null) { + updateSeverity(InvalidJavadoc, optionValue); + } + if ((optionValue = optionsMap.get(OPTION_ReportInvalidJavadocTagsVisibility)) != null) { + if (PUBLIC.equals(optionValue)) { + this.reportInvalidJavadocTagsVisibility = AccPublic; + } else if (PROTECTED.equals(optionValue)) { + this.reportInvalidJavadocTagsVisibility = AccProtected; + } else if (DEFAULT.equals(optionValue)) { + this.reportInvalidJavadocTagsVisibility = AccDefault; + } else if (PRIVATE.equals(optionValue)) { + this.reportInvalidJavadocTagsVisibility = AccPrivate; + } + } + if ((optionValue = optionsMap.get(OPTION_ReportInvalidJavadocTags)) != null) { + if (ENABLED.equals(optionValue)) { + this.reportInvalidJavadocTags= true; + } else if (DISABLED.equals(optionValue)) { + this.reportInvalidJavadocTags = false; + } + } + if ((optionValue = optionsMap.get(OPTION_ReportMissingJavadocTags)) != null) { + updateSeverity(MissingJavadocTags, optionValue); + } + if ((optionValue = optionsMap.get(OPTION_ReportMissingJavadocTagsVisibility)) != null) { + if (PUBLIC.equals(optionValue)) { + this.reportMissingJavadocTagsVisibility = AccPublic; + } else if (PROTECTED.equals(optionValue)) { + this.reportMissingJavadocTagsVisibility = AccProtected; + } else if (DEFAULT.equals(optionValue)) { + this.reportMissingJavadocTagsVisibility = AccDefault; + } else if (PRIVATE.equals(optionValue)) { + this.reportMissingJavadocTagsVisibility = AccPrivate; + } + } + if ((optionValue = optionsMap.get(OPTION_ReportMissingJavadocTagsOverriding)) != null) { + if (ENABLED.equals(optionValue)) { + this.reportMissingJavadocTagsOverriding = true; + } else if (DISABLED.equals(optionValue)) { + this.reportMissingJavadocTagsOverriding = false; + } + } + if ((optionValue = optionsMap.get(OPTION_ReportMissingJavadocComments)) != null) { + updateSeverity(MissingJavadocComments, optionValue); + } + if ((optionValue = optionsMap.get(OPTION_ReportMissingJavadocCommentsVisibility)) != null) { + if (PUBLIC.equals(optionValue)) { + this.reportMissingJavadocCommentsVisibility = AccPublic; + } else if (PROTECTED.equals(optionValue)) { + this.reportMissingJavadocCommentsVisibility = AccProtected; + } else if (DEFAULT.equals(optionValue)) { + this.reportMissingJavadocCommentsVisibility = AccDefault; + } else if (PRIVATE.equals(optionValue)) { + this.reportMissingJavadocCommentsVisibility = AccPrivate; + } + } + if ((optionValue = optionsMap.get(OPTION_ReportMissingJavadocCommentsOverriding)) != null) { + if (ENABLED.equals(optionValue)) { + this.reportMissingJavadocCommentsOverriding = true; + } else if (DISABLED.equals(optionValue)) { + this.reportMissingJavadocCommentsOverriding = false; + } + } + } + + public String toString() { + + StringBuffer buf = new StringBuffer("CompilerOptions:"); //$NON-NLS-1$ + buf.append("\n\t- local variables debug attributes: ").append((this.produceDebugAttributes & Vars) != 0 ? "ON" : " OFF"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + buf.append("\n\t- line number debug attributes: ").append((this.produceDebugAttributes & Lines) != 0 ? "ON" : " OFF"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + buf.append("\n\t- source debug attributes: ").append((this.produceDebugAttributes & Source) != 0 ? "ON" : " OFF"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + buf.append("\n\t- preserve all local variables: ").append(this.preserveAllLocalVariables ? "ON" : " OFF"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + buf.append("\n\t- method with constructor name: ").append(getSeverityString(MethodWithConstructorName)); //$NON-NLS-1$ + buf.append("\n\t- overridden package default method: ").append(getSeverityString(OverriddenPackageDefaultMethod)); //$NON-NLS-1$ + buf.append("\n\t- deprecation: ").append(getSeverityString(UsingDeprecatedAPI)); //$NON-NLS-1$ + buf.append("\n\t- masked catch block: ").append(getSeverityString(MaskedCatchBlock)); //$NON-NLS-1$ + buf.append("\n\t- unused local variable: ").append(getSeverityString(UnusedLocalVariable)); //$NON-NLS-1$ + buf.append("\n\t- unused parameter: ").append(getSeverityString(UnusedArgument)); //$NON-NLS-1$ + buf.append("\n\t- unused import: ").append(getSeverityString(UnusedImport)); //$NON-NLS-1$ + buf.append("\n\t- synthetic access emulation: ").append(getSeverityString(AccessEmulation)); //$NON-NLS-1$ + buf.append("\n\t- assignment with no effect: ").append(getSeverityString(NoEffectAssignment)); //$NON-NLS-1$ + buf.append("\n\t- non externalized string: ").append(getSeverityString(NonExternalizedString)); //$NON-NLS-1$ + buf.append("\n\t- static access receiver: ").append(getSeverityString(NonStaticAccessToStatic)); //$NON-NLS-1$ + buf.append("\n\t- indirect static access: ").append(getSeverityString(IndirectStaticAccess)); //$NON-NLS-1$ + buf.append("\n\t- incompatible non inherited interface method: ").append(getSeverityString(IncompatibleNonInheritedInterfaceMethod)); //$NON-NLS-1$ + buf.append("\n\t- unused private member: ").append(getSeverityString(UnusedPrivateMember)); //$NON-NLS-1$ + buf.append("\n\t- local variable hiding another variable: ").append(getSeverityString(LocalVariableHiding)); //$NON-NLS-1$ + buf.append("\n\t- field hiding another variable: ").append(getSeverityString(FieldHiding)); //$NON-NLS-1$ + buf.append("\n\t- possible accidental boolean assignment: ").append(getSeverityString(AccidentalBooleanAssign)); //$NON-NLS-1$ + buf.append("\n\t- superfluous semicolon: ").append(getSeverityString(EmptyStatement)); //$NON-NLS-1$ + buf.append("\n\t- uncommented empty block: ").append(getSeverityString(UndocumentedEmptyBlock)); //$NON-NLS-1$ + buf.append("\n\t- unnecessary type check: ").append(getSeverityString(UnnecessaryTypeCheck)); //$NON-NLS-1$ + buf.append("\n\t- javadoc comment support: ").append(this.docCommentSupport ? "ON" : " OFF"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + buf.append("\n\t\t+ invalid javadoc: ").append(getSeverityString(InvalidJavadoc)); //$NON-NLS-1$ + buf.append("\n\t\t+ report invalid javadoc tags: ").append(this.reportInvalidJavadocTags ? ENABLED : DISABLED); //$NON-NLS-1$ + buf.append("\n\t\t+ visibility level to report invalid javadoc tags: ").append(getVisibilityString(this.reportInvalidJavadocTagsVisibility)); //$NON-NLS-1$ + buf.append("\n\t\t+ missing javadoc tags: ").append(getSeverityString(MissingJavadocTags)); //$NON-NLS-1$ + buf.append("\n\t\t+ visibility level to report missing javadoc tags: ").append(getVisibilityString(this.reportMissingJavadocTagsVisibility)); //$NON-NLS-1$ + buf.append("\n\t\t+ report missing javadoc tags in overriding methods: ").append(this.reportMissingJavadocTagsOverriding ? ENABLED : DISABLED); //$NON-NLS-1$ + buf.append("\n\t\t+ missing javadoc comments: ").append(getSeverityString(MissingJavadocComments)); //$NON-NLS-1$ + buf.append("\n\t\t+ visibility level to report missing javadoc comments: ").append(getVisibilityString(this.reportMissingJavadocCommentsVisibility)); //$NON-NLS-1$ + buf.append("\n\t\t+ report missing javadoc comments in overriding methods: ").append(this.reportMissingJavadocCommentsOverriding ? ENABLED : DISABLED); //$NON-NLS-1$ + buf.append("\n\t- finally block not completing normally: ").append(getSeverityString(FinallyBlockNotCompleting)); //$NON-NLS-1$ + buf.append("\n\t- unused declared thrown exception: ").append(getSeverityString(UnusedDeclaredThrownException)); //$NON-NLS-1$ + buf.append("\n\t- unused declared thrown exception when overriding: ").append(this.reportUnusedDeclaredThrownExceptionWhenOverriding ? ENABLED : DISABLED); //$NON-NLS-1$ + buf.append("\n\t- unnecessary else: ").append(getSeverityString(UnnecessaryElse)); //$NON-NLS-1$ + buf.append("\n\t- JDK compliance level: "+ versionFromJdkLevel(this.complianceLevel)); //$NON-NLS-1$ + buf.append("\n\t- JDK source level: "+ versionFromJdkLevel(this.sourceLevel)); //$NON-NLS-1$ + buf.append("\n\t- JDK target level: "+ versionFromJdkLevel(this.targetJDK)); //$NON-NLS-1$ + buf.append("\n\t- private constructor access: ").append(this.isPrivateConstructorAccessChangingVisibility ? "extra argument" : "make default access"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + buf.append("\n\t- verbose : ").append(this.verbose ? "ON" : "OFF"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + buf.append("\n\t- produce reference info : ").append(this.produceReferenceInfo ? "ON" : "OFF"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + buf.append("\n\t- parse literal expressions as constants : ").append(this.parseLiteralExpressionsAsConstants ? "ON" : "OFF"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + buf.append("\n\t- encoding : ").append(this.defaultEncoding == null ? "" : this.defaultEncoding); //$NON-NLS-1$ //$NON-NLS-2$ + buf.append("\n\t- task tags: ").append(this.taskTags == null ? "" : new String(CharOperation.concatWith(this.taskTags,','))); //$NON-NLS-1$ //$NON-NLS-2$ + buf.append("\n\t- task priorities : ").append(this.taskPriorites == null ? "" : new String(CharOperation.concatWith(this.taskPriorites,','))); //$NON-NLS-1$ //$NON-NLS-2$ + buf.append("\n\t- report deprecation inside deprecated code : ").append(this.reportDeprecationInsideDeprecatedCode ? ENABLED : DISABLED); //$NON-NLS-1$ + buf.append("\n\t- report deprecation when overriding deprecated method : ").append(this.reportDeprecationWhenOverridingDeprecatedMethod ? ENABLED : DISABLED); //$NON-NLS-1$ + buf.append("\n\t- report unused parameter when implementing abstract method : ").append(this.reportUnusedParameterWhenImplementingAbstract ? ENABLED : DISABLED); //$NON-NLS-1$ + buf.append("\n\t- report unused parameter when overriding concrete method : ").append(this.reportUnusedParameterWhenOverridingConcrete ? ENABLED : DISABLED); //$NON-NLS-1$ + buf.append("\n\t- report constructor/setter parameter hiding existing field : ").append(this.reportSpecialParameterHidingField ? ENABLED : DISABLED); //$NON-NLS-1$ + buf.append("\n\t- inline JSR bytecode : ").append(this.inlineJsrBytecode ? ENABLED : DISABLED); //$NON-NLS-1$ + return buf.toString(); + } + + void updateSeverity(long irritant, Object severityString) { + if (ERROR.equals(severityString)) { + this.errorThreshold |= irritant; + this.warningThreshold &= ~irritant; + } else if (WARNING.equals(severityString)) { + this.errorThreshold &= ~irritant; + this.warningThreshold |= irritant; + } else if (IGNORE.equals(severityString)) { + this.errorThreshold &= ~irritant; + this.warningThreshold &= ~irritant; + } + } + public static long versionToJdkLevel(Object versionID) { + if (VERSION_1_1.equals(versionID)) { + return JDK1_1; + } else if (VERSION_1_2.equals(versionID)) { + return JDK1_2; + } else if (VERSION_1_3.equals(versionID)) { + return JDK1_3; + } else if (VERSION_1_4.equals(versionID)) { + return JDK1_4; + } else if (VERSION_1_5.equals(versionID)) { + return JDK1_5; + } + return 0; // unknown + } + + public static String versionFromJdkLevel(long jdkLevel) { + if (jdkLevel == JDK1_1) { + return VERSION_1_1; + } else if (jdkLevel == JDK1_2) { + return VERSION_1_2; + } else if (jdkLevel == JDK1_3) { + return VERSION_1_3; + } else if (jdkLevel == JDK1_4) { + return VERSION_1_4; + } else if (jdkLevel == JDK1_5) { + return VERSION_1_5; + } + return ""; // unknown version //$NON-NLS-1$ + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/impl/Constant.java b/src/java/org/eclipse/jdt/internal/compiler/impl/Constant.java new file mode 100644 index 0000000..f82b409 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/impl/Constant.java @@ -0,0 +1,1611 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.impl; + +import org.eclipse.jdt.internal.compiler.ast.OperatorIds; +import org.eclipse.jdt.internal.compiler.lookup.TypeIds; +import org.eclipse.jdt.internal.compiler.problem.ShouldNotImplement; +import org.eclipse.jdt.internal.compiler.util.Util; + +public abstract class Constant implements TypeIds, OperatorIds { + + public static final Constant NotAConstant = new DoubleConstant(Double.NaN); + + public static final IntConstant Zero = new IntConstant(0); + public static final IntConstant Two = new IntConstant(2); + public static final IntConstant One = new IntConstant(1); + + public boolean booleanValue() { + + throw new ShouldNotImplement(Util.bind("constant.cannotCastedInto",typeName(),"boolean")); //$NON-NLS-1$ //$NON-NLS-2$ + } + + public byte byteValue() { + + throw new ShouldNotImplement(Util.bind("constant.cannotCastedInto",typeName(),"byte")); //$NON-NLS-1$ //$NON-NLS-2$ + } + + public final Constant castTo(int conversionToTargetType){ + //the cast is an int of the form + // (castId<<4)+typeId (in order to follow the + //user written style (cast)expression .... + + if (this == NotAConstant) return NotAConstant; + switch(conversionToTargetType){ + case T_undefined : return this; + // TARGET TYPE <- FROM TYPE + // case (T_undefined<<4)+T_undefined : return NotAConstant; + // case (T_undefined<<4)+T_byte : return NotAConstant; + // case (T_undefined<<4)+T_long : return NotAConstant; + // case (T_undefined<<4)+T_short : return NotAConstant; + // case (T_undefined<<4)+T_void : return NotAConstant; + // case (T_undefined<<4)+T_String : return NotAConstant; + // case (T_undefined<<4)+T_Object : return NotAConstant; + // case (T_undefined<<4)+T_double : return NotAConstant; + // case (T_undefined<<4)+T_float : return NotAConstant; + // case (T_undefined<<4)+T_boolean : return NotAConstant; + // case (T_undefined<<4)+T_char : return NotAConstant; + // case (T_undefined<<4)+T_int : return NotAConstant; + + // case (T_byte<<4)+T_undefined : return NotAConstant; + case (T_byte<<4)+T_byte : return this; + case (T_byte<<4)+T_long : return Constant.fromValue((byte)this.longValue()); + case (T_byte<<4)+T_short : return Constant.fromValue((byte)this.shortValue()); + // case (T_byte<<4)+T_void : return NotAConstant; + // case (T_byte<<4)+T_String : return NotAConstant; + // case (T_byte<<4)+T_Object : return NotAConstant; + case (T_byte<<4)+T_double : return Constant.fromValue((byte)this.doubleValue()); + case (T_byte<<4)+T_float : return Constant.fromValue((byte)this.floatValue()); + // case (T_byte<<4)+T_boolean : return NotAConstant; + case (T_byte<<4)+T_char : return Constant.fromValue((byte)this.charValue()); + case (T_byte<<4)+T_int : return Constant.fromValue((byte)this.intValue()); + + // case (T_long<<4)+T_undefined : return NotAConstant; + case (T_long<<4)+T_byte : return Constant.fromValue((long)this.byteValue()); + case (T_long<<4)+T_long : return this; + case (T_long<<4)+T_short : return Constant.fromValue((long)this.shortValue()); + // case (T_long<<4)+T_void : return NotAConstant; + // case (T_long<<4)+T_String : return NotAConstant; + // case (T_long<<4)+T_Object : return NotAConstant; + case (T_long<<4)+T_double : return Constant.fromValue((long)this.doubleValue()); + case (T_long<<4)+T_float : return Constant.fromValue((long)this.floatValue()); + // case (T_long<<4)+T_boolean : return NotAConstant; + case (T_long<<4)+T_char : return Constant.fromValue((long)this.charValue()); + case (T_long<<4)+T_int : return Constant.fromValue((long)this.intValue()); + + // case (T_short<<4)+T_undefined : return NotAConstant; + case (T_short<<4)+T_byte : return Constant.fromValue((short)this.byteValue()); + case (T_short<<4)+T_long : return Constant.fromValue((short)this.longValue()); + case (T_short<<4)+T_short : return this; + // case (T_short<<4)+T_void : return NotAConstant; + // case (T_short<<4)+T_String : return NotAConstant; + // case (T_short<<4)+T_Object : return NotAConstant; + case (T_short<<4)+T_double : return Constant.fromValue((short)this.doubleValue()); + case (T_short<<4)+T_float : return Constant.fromValue((short)this.floatValue()); + // case (T_short<<4)+T_boolean : return NotAConstant; + case (T_short<<4)+T_char : return Constant.fromValue((short)this.charValue()); + case (T_short<<4)+T_int : return Constant.fromValue((short)this.intValue()); + + // case (T_void<<4)+T_undefined : return NotAConstant; + // case (T_void<<4)+T_byte : return NotAConstant; + // case (T_void<<4)+T_long : return NotAConstant; + // case (T_void<<4)+T_short : return NotAConstant; + // case (T_void<<4)+T_void : return NotAConstant; + // case (T_void<<4)+T_String : return NotAConstant; + // case (T_void<<4)+T_Object : return NotAConstant; + // case (T_void<<4)+T_double : return NotAConstant; + // case (T_void<<4)+T_float : return NotAConstant; + // case (T_void<<4)+T_boolean : return NotAConstant; + // case (T_void<<4)+T_char : return NotAConstant; + // case (T_void<<4)+T_int : return NotAConstant; + + // case (T_String<<4)+T_undefined : return NotAConstant; + // case (T_String<<4)+T_byte : return NotAConstant; + // case (T_String<<4)+T_long : return NotAConstant; + // case (T_String<<4)+T_short : return NotAConstant; + // case (T_String<<4)+T_void : return NotAConstant; + case (T_String<<4)+T_String : return this; + // case (T_String<<4)+T_Object : return NotAConstant; + // case (T_String<<4)+T_double : return NotAConstant; + // case (T_String<<4)+T_float : return NotAConstant; + // case (T_String<<4)+T_boolean : return NotAConstant; + // case (T_String<<4)+T_char : return NotAConstant; + // case (T_String<<4)+T_int : return NotAConstant; + + // case (T_Object<<4)+T_undefined : return NotAConstant; + // case (T_Object<<4)+T_byte : return NotAConstant; + // case (T_Object<<4)+T_long : return NotAConstant; + // case (T_Object<<4)+T_short : return NotAConstant; + // case (T_Object<<4)+T_void : return NotAConstant; + // case (T_Object<<4)+T_String : return NotAConstant; + // case (T_Object<<4)+T_Object : return NotAConstant; + // case (T_Object<<4)+T_double : return NotAConstant; + // case (T_Object<<4)+T_float : return NotAConstant; + // case (T_Object<<4)+T_boolean : return NotAConstant; + // case (T_Object<<4)+T_char : return NotAConstant; + // case (T_Object<<4)+T_int : return NotAConstant; + + // case (T_double<<4)+T_undefined : return NotAConstant; + case (T_double<<4)+T_byte : return Constant.fromValue((double)this.byteValue()); + case (T_double<<4)+T_long : return Constant.fromValue((double)this.longValue()); + case (T_double<<4)+T_short : return Constant.fromValue((double)this.shortValue()); + // case (T_double<<4)+T_void : return NotAConstant; + // case (T_double<<4)+T_String : return NotAConstant; + // case (T_double<<4)+T_Object : return NotAConstant; + case (T_double<<4)+T_double : return this; + case (T_double<<4)+T_float : return Constant.fromValue((double)this.floatValue()); + // case (T_double<<4)+T_boolean : return NotAConstant; + case (T_double<<4)+T_char : return Constant.fromValue((double)this.charValue()); + case (T_double<<4)+T_int : return Constant.fromValue((double)this.intValue()); + + // case (T_float<<4)+T_undefined : return NotAConstant; + case (T_float<<4)+T_byte : return Constant.fromValue((float)this.byteValue()); + case (T_float<<4)+T_long : return Constant.fromValue((float)this.longValue()); + case (T_float<<4)+T_short : return Constant.fromValue((float)this.shortValue()); + // case (T_float<<4)+T_void : return NotAConstant; + // case (T_float<<4)+T_String : return NotAConstant; + // case (T_float<<4)+T_Object : return NotAConstant; + case (T_float<<4)+T_double : return Constant.fromValue((float)this.doubleValue()); + case (T_float<<4)+T_float : return this; + // case (T_float<<4)+T_boolean : return NotAConstant; + case (T_float<<4)+T_char : return Constant.fromValue((float)this.charValue()); + case (T_float<<4)+T_int : return Constant.fromValue((float)this.intValue()); + + // case (T_boolean<<4)+T_undefined : return NotAConstant; + // case (T_boolean<<4)+T_byte : return NotAConstant; + // case (T_boolean<<4)+T_long : return NotAConstant; + // case (T_boolean<<4)+T_short : return NotAConstant; + // case (T_boolean<<4)+T_void : return NotAConstant; + // case (T_boolean<<4)+T_String : return NotAConstant; + // case (T_boolean<<4)+T_Object : return NotAConstant; + // case (T_boolean<<4)+T_double : return NotAConstant; + // case (T_boolean<<4)+T_float : return NotAConstant; + case (T_boolean<<4)+T_boolean : return this; + // case (T_boolean<<4)+T_char : return NotAConstant; + // case (T_boolean<<4)+T_int : return NotAConstant; + + // case (T_char<<4)+T_undefined : return NotAConstant; + case (T_char<<4)+T_byte : return Constant.fromValue((char)this.byteValue()); + case (T_char<<4)+T_long : return Constant.fromValue((char)this.longValue()); + case (T_char<<4)+T_short : return Constant.fromValue((char)this.shortValue()); + // case (T_char<<4)+T_void : return NotAConstant; + // case (T_char<<4)+T_String : return NotAConstant; + // case (T_char<<4)+T_Object : return NotAConstant; + case (T_char<<4)+T_double : return Constant.fromValue((char)this.doubleValue()); + case (T_char<<4)+T_float : return Constant.fromValue((char)this.floatValue()); + // case (T_char<<4)+T_boolean : return NotAConstant; + case (T_char<<4)+T_char : return this; + case (T_char<<4)+T_int : return Constant.fromValue((char)this.intValue()); + + // case (T_int<<4)+T_undefined : return NotAConstant; + case (T_int<<4)+T_byte : return Constant.fromValue((int)this.byteValue()); + case (T_int<<4)+T_long : return Constant.fromValue((int)this.longValue()); + case (T_int<<4)+T_short : return Constant.fromValue((int)this.shortValue()); + // case (T_int<<4)+T_void : return NotAConstant; + // case (T_int<<4)+T_String : return NotAConstant; + // case (T_int<<4)+T_Object : return NotAConstant; + case (T_int<<4)+T_double : return Constant.fromValue((int)this.doubleValue()); + case (T_int<<4)+T_float : return Constant.fromValue((int)this.floatValue()); + // case (T_int<<4)+T_boolean : return NotAConstant; + case (T_int<<4)+T_char : return Constant.fromValue((int)this.charValue()); + case (T_int<<4)+T_int : return this; + + } + + return NotAConstant; + } + + public char charValue() { + + throw new ShouldNotImplement(Util.bind("constant.cannotCastedInto",typeName(),"char")); //$NON-NLS-1$ //$NON-NLS-2$ + } + + public static final Constant computeConstantOperation(Constant cst, int id, int operator) { + + switch (operator) { + case NOT : + return Constant.fromValue(!cst.booleanValue()); + case PLUS : return cst; + case MINUS : //the two special -9223372036854775808L and -2147483648 are inlined at parseTime + switch (id){ + case T_float : float f; + if ( (f= cst.floatValue()) == 0.0f) + { //positive and negative 0.... + if (Float.floatToIntBits(f) == 0) + return Constant.fromValue(-0.0f); + else + return Constant.fromValue(0.0f);} + break; //default case + case T_double : double d; + if ( (d= cst.doubleValue()) == 0.0d) + { //positive and negative 0.... + if (Double.doubleToLongBits(d) == 0) + return Constant.fromValue(-0.0d); + else + return Constant.fromValue(0.0d);} + break; //default case + } + return computeConstantOperationMINUS(Zero,T_int,operator,cst,id); + case TWIDDLE: + switch (id){ + case T_char : return Constant.fromValue(~ cst.charValue()); + case T_byte: return Constant.fromValue(~ cst.byteValue()); + case T_short: return Constant.fromValue(~ cst.shortValue()); + case T_int: return Constant.fromValue(~ cst.intValue()); + case T_long: return Constant.fromValue(~ cst.longValue()); + default : return NotAConstant; + } + default : return NotAConstant; + } + } + + public static final Constant computeConstantOperation(Constant left, int leftId, int operator, Constant right, int rightId) { + + switch (operator) { + case AND : return computeConstantOperationAND (left,leftId,operator,right,rightId); + case AND_AND : return computeConstantOperationAND_AND (left,leftId,operator,right,rightId); + case DIVIDE : return computeConstantOperationDIVIDE (left,leftId,operator,right,rightId); + case GREATER : return computeConstantOperationGREATER (left,leftId,operator,right,rightId); + case GREATER_EQUAL : return computeConstantOperationGREATER_EQUAL(left,leftId,operator,right,rightId); + case LEFT_SHIFT : return computeConstantOperationLEFT_SHIFT (left,leftId,operator,right,rightId); + case LESS : return computeConstantOperationLESS (left,leftId,operator,right,rightId); + case LESS_EQUAL : return computeConstantOperationLESS_EQUAL (left,leftId,operator,right,rightId); + case MINUS : return computeConstantOperationMINUS (left,leftId,operator,right,rightId); + case MULTIPLY : return computeConstantOperationMULTIPLY (left,leftId,operator,right,rightId); + case OR : return computeConstantOperationOR (left,leftId,operator,right,rightId); + case OR_OR : return computeConstantOperationOR_OR (left,leftId,operator,right,rightId); + case PLUS : return computeConstantOperationPLUS (left,leftId,operator,right,rightId); + case REMAINDER : return computeConstantOperationREMAINDER (left,leftId,operator,right,rightId); + case RIGHT_SHIFT: return computeConstantOperationRIGHT_SHIFT(left,leftId,operator,right,rightId); + case UNSIGNED_RIGHT_SHIFT: return computeConstantOperationUNSIGNED_RIGHT_SHIFT(left,leftId,operator,right,rightId); + case XOR : return computeConstantOperationXOR (left,leftId,operator,right,rightId); + + default : return NotAConstant; + } + } + + public static final Constant computeConstantOperationAND(Constant left, int leftId, int operator, Constant right, int rightId) { + + switch (leftId){ + case T_boolean : return Constant.fromValue(left.booleanValue() & right.booleanValue()); + case T_char : + switch (rightId){ + case T_char : return Constant.fromValue(left.charValue() & right.charValue()); + case T_byte: return Constant.fromValue(left.charValue() & right.byteValue()); + case T_short: return Constant.fromValue(left.charValue() & right.shortValue()); + case T_int: return Constant.fromValue(left.charValue() & right.intValue()); + case T_long: return Constant.fromValue(left.charValue() & right.longValue()); + } + break; + case T_byte : + switch (rightId){ + case T_char : return Constant.fromValue(left.byteValue() & right.charValue()); + case T_byte: return Constant.fromValue(left.byteValue() & right.byteValue()); + case T_short: return Constant.fromValue(left.byteValue() & right.shortValue()); + case T_int: return Constant.fromValue(left.byteValue() & right.intValue()); + case T_long: return Constant.fromValue(left.byteValue() & right.longValue()); + } + break; + case T_short : + switch (rightId){ + case T_char : return Constant.fromValue(left.shortValue() & right.charValue()); + case T_byte: return Constant.fromValue(left.shortValue() & right.byteValue()); + case T_short: return Constant.fromValue(left.shortValue() & right.shortValue()); + case T_int: return Constant.fromValue(left.shortValue() & right.intValue()); + case T_long: return Constant.fromValue(left.shortValue() & right.longValue()); + } + break; + case T_int : + switch (rightId){ + case T_char : return Constant.fromValue(left.intValue() & right.charValue()); + case T_byte: return Constant.fromValue(left.intValue() & right.byteValue()); + case T_short: return Constant.fromValue(left.intValue() & right.shortValue()); + case T_int: return Constant.fromValue(left.intValue() & right.intValue()); + case T_long: return Constant.fromValue(left.intValue() & right.longValue()); + } + break; + case T_long : + switch (rightId){ + case T_char : return Constant.fromValue(left.longValue() & right.charValue()); + case T_byte: return Constant.fromValue(left.longValue() & right.byteValue()); + case T_short: return Constant.fromValue(left.longValue() & right.shortValue()); + case T_int: return Constant.fromValue(left.longValue() & right.intValue()); + case T_long: return Constant.fromValue(left.longValue() & right.longValue()); + } + } + + return NotAConstant; + } + + public static final Constant computeConstantOperationAND_AND(Constant left, int leftId, int operator, Constant right, int rightId) { + + return Constant.fromValue(left.booleanValue() && right.booleanValue()); + } + + public static final Constant computeConstantOperationDIVIDE(Constant left, int leftId, int operator, Constant right, int rightId) { + // division by zero must be handled outside this method (error reporting) + + switch (leftId){ + case T_char : + switch (rightId){ + case T_char : return Constant.fromValue(left.charValue() / right.charValue()); + case T_float: return Constant.fromValue(left.charValue() / right.floatValue()); + case T_double: return Constant.fromValue(left.charValue() / right.doubleValue()); + case T_byte: return Constant.fromValue(left.charValue() / right.byteValue()); + case T_short: return Constant.fromValue(left.charValue() / right.shortValue()); + case T_int: return Constant.fromValue(left.charValue() / right.intValue()); + case T_long: return Constant.fromValue(left.charValue() / right.longValue()); + } + break; + case T_float : + switch (rightId){ + case T_char : return Constant.fromValue(left.floatValue() / right.charValue()); + case T_float: return Constant.fromValue(left.floatValue() / right.floatValue()); + case T_double: return Constant.fromValue(left.floatValue() / right.doubleValue()); + case T_byte: return Constant.fromValue(left.floatValue() / right.byteValue()); + case T_short: return Constant.fromValue(left.floatValue() / right.shortValue()); + case T_int: return Constant.fromValue(left.floatValue() / right.intValue()); + case T_long: return Constant.fromValue(left.floatValue() / right.longValue()); + } + break; + case T_double : + switch (rightId){ + case T_char : return Constant.fromValue(left.doubleValue() / right.charValue()); + case T_float: return Constant.fromValue(left.doubleValue() / right.floatValue()); + case T_double: return Constant.fromValue(left.doubleValue() / right.doubleValue()); + case T_byte: return Constant.fromValue(left.doubleValue() / right.byteValue()); + case T_short: return Constant.fromValue(left.doubleValue() / right.shortValue()); + case T_int: return Constant.fromValue(left.doubleValue() / right.intValue()); + case T_long: return Constant.fromValue(left.doubleValue() / right.longValue()); + } + break; + case T_byte : + switch (rightId){ + case T_char : return Constant.fromValue(left.byteValue() / right.charValue()); + case T_float: return Constant.fromValue(left.byteValue() / right.floatValue()); + case T_double: return Constant.fromValue(left.byteValue() / right.doubleValue()); + case T_byte: return Constant.fromValue(left.byteValue() / right.byteValue()); + case T_short: return Constant.fromValue(left.byteValue() / right.shortValue()); + case T_int: return Constant.fromValue(left.byteValue() / right.intValue()); + case T_long: return Constant.fromValue(left.byteValue() / right.longValue()); + } + break; + case T_short : + switch (rightId){ + case T_char : return Constant.fromValue(left.shortValue() / right.charValue()); + case T_float: return Constant.fromValue(left.shortValue() / right.floatValue()); + case T_double: return Constant.fromValue(left.shortValue() / right.doubleValue()); + case T_byte: return Constant.fromValue(left.shortValue() / right.byteValue()); + case T_short: return Constant.fromValue(left.shortValue() / right.shortValue()); + case T_int: return Constant.fromValue(left.shortValue() / right.intValue()); + case T_long: return Constant.fromValue(left.shortValue() / right.longValue()); + } + break; + case T_int : + switch (rightId){ + case T_char : return Constant.fromValue(left.intValue() / right.charValue()); + case T_float: return Constant.fromValue(left.intValue() / right.floatValue()); + case T_double: return Constant.fromValue(left.intValue() / right.doubleValue()); + case T_byte: return Constant.fromValue(left.intValue() / right.byteValue()); + case T_short: return Constant.fromValue(left.intValue() / right.shortValue()); + case T_int: return Constant.fromValue(left.intValue() / right.intValue()); + case T_long: return Constant.fromValue(left.intValue() / right.longValue()); + } + break; + case T_long : + switch (rightId){ + case T_char : return Constant.fromValue(left.longValue() / right.charValue()); + case T_float: return Constant.fromValue(left.longValue() / right.floatValue()); + case T_double: return Constant.fromValue(left.longValue() / right.doubleValue()); + case T_byte: return Constant.fromValue(left.longValue() / right.byteValue()); + case T_short: return Constant.fromValue(left.longValue() / right.shortValue()); + case T_int: return Constant.fromValue(left.longValue() / right.intValue()); + case T_long: return Constant.fromValue(left.longValue() / right.longValue()); + } + + } + + return NotAConstant; + } + + public static final Constant computeConstantOperationEQUAL_EQUAL(Constant left, int leftId, int operator, Constant right, int rightId) { + + switch (leftId){ + case T_boolean : + if (rightId == T_boolean) { + return Constant.fromValue(left.booleanValue() == right.booleanValue()); + } + break; + case T_char : + switch (rightId){ + case T_char : return Constant.fromValue(left.charValue() == right.charValue()); + case T_float: return Constant.fromValue(left.charValue() == right.floatValue()); + case T_double: return Constant.fromValue(left.charValue() == right.doubleValue()); + case T_byte: return Constant.fromValue(left.charValue() == right.byteValue()); + case T_short: return Constant.fromValue(left.charValue() == right.shortValue()); + case T_int: return Constant.fromValue(left.charValue() == right.intValue()); + case T_long: return Constant.fromValue(left.charValue() == right.longValue());} + break; + case T_float : + switch (rightId){ + case T_char : return Constant.fromValue(left.floatValue() == right.charValue()); + case T_float: return Constant.fromValue(left.floatValue() == right.floatValue()); + case T_double: return Constant.fromValue(left.floatValue() == right.doubleValue()); + case T_byte: return Constant.fromValue(left.floatValue() == right.byteValue()); + case T_short: return Constant.fromValue(left.floatValue() == right.shortValue()); + case T_int: return Constant.fromValue(left.floatValue() == right.intValue()); + case T_long: return Constant.fromValue(left.floatValue() == right.longValue()); + } + break; + case T_double : + switch (rightId){ + case T_char : return Constant.fromValue(left.doubleValue() == right.charValue()); + case T_float: return Constant.fromValue(left.doubleValue() == right.floatValue()); + case T_double: return Constant.fromValue(left.doubleValue() == right.doubleValue()); + case T_byte: return Constant.fromValue(left.doubleValue() == right.byteValue()); + case T_short: return Constant.fromValue(left.doubleValue() == right.shortValue()); + case T_int: return Constant.fromValue(left.doubleValue() == right.intValue()); + case T_long: return Constant.fromValue(left.doubleValue() == right.longValue()); + } + break; + case T_byte : + switch (rightId){ + case T_char : return Constant.fromValue(left.byteValue() == right.charValue()); + case T_float: return Constant.fromValue(left.byteValue() == right.floatValue()); + case T_double: return Constant.fromValue(left.byteValue() == right.doubleValue()); + case T_byte: return Constant.fromValue(left.byteValue() == right.byteValue()); + case T_short: return Constant.fromValue(left.byteValue() == right.shortValue()); + case T_int: return Constant.fromValue(left.byteValue() == right.intValue()); + case T_long: return Constant.fromValue(left.byteValue() == right.longValue()); + } + break; + case T_short : + switch (rightId){ + case T_char : return Constant.fromValue(left.shortValue() == right.charValue()); + case T_float: return Constant.fromValue(left.shortValue() == right.floatValue()); + case T_double: return Constant.fromValue(left.shortValue() == right.doubleValue()); + case T_byte: return Constant.fromValue(left.shortValue() == right.byteValue()); + case T_short: return Constant.fromValue(left.shortValue() == right.shortValue()); + case T_int: return Constant.fromValue(left.shortValue() == right.intValue()); + case T_long: return Constant.fromValue(left.shortValue() == right.longValue()); + } + break; + case T_int : + switch (rightId){ + case T_char : return Constant.fromValue(left.intValue() == right.charValue()); + case T_float: return Constant.fromValue(left.intValue() == right.floatValue()); + case T_double: return Constant.fromValue(left.intValue() == right.doubleValue()); + case T_byte: return Constant.fromValue(left.intValue() == right.byteValue()); + case T_short: return Constant.fromValue(left.intValue() == right.shortValue()); + case T_int: return Constant.fromValue(left.intValue() == right.intValue()); + case T_long: return Constant.fromValue(left.intValue() == right.longValue()); + } + break; + case T_long : + switch (rightId){ + case T_char : return Constant.fromValue(left.longValue() == right.charValue()); + case T_float: return Constant.fromValue(left.longValue() == right.floatValue()); + case T_double: return Constant.fromValue(left.longValue() == right.doubleValue()); + case T_byte: return Constant.fromValue(left.longValue() == right.byteValue()); + case T_short: return Constant.fromValue(left.longValue() == right.shortValue()); + case T_int: return Constant.fromValue(left.longValue() == right.intValue()); + case T_long: return Constant.fromValue(left.longValue() == right.longValue()); + } + break; + case T_String : + if (rightId == T_String) { + //String are interned in th compiler==>thus if two string constant + //get to be compared, it is an equal on the vale which is done + return Constant.fromValue(((StringConstant)left).compileTimeEqual((StringConstant)right)); + } + break; + case T_null : + if (rightId == T_String) { + return Constant.fromValue(false); + } else { + if (rightId == T_null) { + return Constant.fromValue(true); + } + } + } + + return Constant.fromValue(false); + } + + public static final Constant computeConstantOperationGREATER(Constant left, int leftId, int operator, Constant right, int rightId) { + + switch (leftId){ + case T_char : + switch (rightId){ + case T_char : return Constant.fromValue(left.charValue() > right.charValue()); + case T_float: return Constant.fromValue(left.charValue() > right.floatValue()); + case T_double: return Constant.fromValue(left.charValue() > right.doubleValue()); + case T_byte: return Constant.fromValue(left.charValue() > right.byteValue()); + case T_short: return Constant.fromValue(left.charValue() > right.shortValue()); + case T_int: return Constant.fromValue(left.charValue() > right.intValue()); + case T_long: return Constant.fromValue(left.charValue() > right.longValue()); + } + break; + case T_float : + switch (rightId){ + case T_char : return Constant.fromValue(left.floatValue() > right.charValue()); + case T_float: return Constant.fromValue(left.floatValue() > right.floatValue()); + case T_double: return Constant.fromValue(left.floatValue() > right.doubleValue()); + case T_byte: return Constant.fromValue(left.floatValue() > right.byteValue()); + case T_short: return Constant.fromValue(left.floatValue() > right.shortValue()); + case T_int: return Constant.fromValue(left.floatValue() > right.intValue()); + case T_long: return Constant.fromValue(left.floatValue() > right.longValue()); + } + break; + case T_double : + switch (rightId){ + case T_char : return Constant.fromValue(left.doubleValue() > right.charValue()); + case T_float: return Constant.fromValue(left.doubleValue() > right.floatValue()); + case T_double: return Constant.fromValue(left.doubleValue() > right.doubleValue()); + case T_byte: return Constant.fromValue(left.doubleValue() > right.byteValue()); + case T_short: return Constant.fromValue(left.doubleValue() > right.shortValue()); + case T_int: return Constant.fromValue(left.doubleValue() > right.intValue()); + case T_long: return Constant.fromValue(left.doubleValue() > right.longValue()); + } + break; + case T_byte : + switch (rightId){ + case T_char : return Constant.fromValue(left.byteValue() > right.charValue()); + case T_float: return Constant.fromValue(left.byteValue() > right.floatValue()); + case T_double: return Constant.fromValue(left.byteValue() > right.doubleValue()); + case T_byte: return Constant.fromValue(left.byteValue() > right.byteValue()); + case T_short: return Constant.fromValue(left.byteValue() > right.shortValue()); + case T_int: return Constant.fromValue(left.byteValue() > right.intValue()); + case T_long: return Constant.fromValue(left.byteValue() > right.longValue()); + } + break; + case T_short : + switch (rightId){ + case T_char : return Constant.fromValue(left.shortValue() > right.charValue()); + case T_float: return Constant.fromValue(left.shortValue() > right.floatValue()); + case T_double: return Constant.fromValue(left.shortValue() > right.doubleValue()); + case T_byte: return Constant.fromValue(left.shortValue() > right.byteValue()); + case T_short: return Constant.fromValue(left.shortValue() > right.shortValue()); + case T_int: return Constant.fromValue(left.shortValue() > right.intValue()); + case T_long: return Constant.fromValue(left.shortValue() > right.longValue()); + } + break; + case T_int : + switch (rightId){ + case T_char : return Constant.fromValue(left.intValue() > right.charValue()); + case T_float: return Constant.fromValue(left.intValue() > right.floatValue()); + case T_double: return Constant.fromValue(left.intValue() > right.doubleValue()); + case T_byte: return Constant.fromValue(left.intValue() > right.byteValue()); + case T_short: return Constant.fromValue(left.intValue() > right.shortValue()); + case T_int: return Constant.fromValue(left.intValue() > right.intValue()); + case T_long: return Constant.fromValue(left.intValue() > right.longValue()); + } + break; + case T_long : + switch (rightId){ + case T_char : return Constant.fromValue(left.longValue() > right.charValue()); + case T_float: return Constant.fromValue(left.longValue() > right.floatValue()); + case T_double: return Constant.fromValue(left.longValue() > right.doubleValue()); + case T_byte: return Constant.fromValue(left.longValue() > right.byteValue()); + case T_short: return Constant.fromValue(left.longValue() > right.shortValue()); + case T_int: return Constant.fromValue(left.longValue() > right.intValue()); + case T_long: return Constant.fromValue(left.longValue() > right.longValue()); + } + + } + + return NotAConstant; + } + + public static final Constant computeConstantOperationGREATER_EQUAL(Constant left, int leftId, int operator, Constant right, int rightId) { + + switch (leftId){ + case T_char : + switch (rightId){ + case T_char : return Constant.fromValue(left.charValue() >= right.charValue()); + case T_float: return Constant.fromValue(left.charValue() >= right.floatValue()); + case T_double: return Constant.fromValue(left.charValue() >= right.doubleValue()); + case T_byte: return Constant.fromValue(left.charValue() >= right.byteValue()); + case T_short: return Constant.fromValue(left.charValue() >= right.shortValue()); + case T_int: return Constant.fromValue(left.charValue() >= right.intValue()); + case T_long: return Constant.fromValue(left.charValue() >= right.longValue()); + } + break; + case T_float : + switch (rightId){ + case T_char : return Constant.fromValue(left.floatValue() >= right.charValue()); + case T_float: return Constant.fromValue(left.floatValue() >= right.floatValue()); + case T_double: return Constant.fromValue(left.floatValue() >= right.doubleValue()); + case T_byte: return Constant.fromValue(left.floatValue() >= right.byteValue()); + case T_short: return Constant.fromValue(left.floatValue() >= right.shortValue()); + case T_int: return Constant.fromValue(left.floatValue() >= right.intValue()); + case T_long: return Constant.fromValue(left.floatValue() >= right.longValue()); + } + break; + case T_double : + switch (rightId){ + case T_char : return Constant.fromValue(left.doubleValue() >= right.charValue()); + case T_float: return Constant.fromValue(left.doubleValue() >= right.floatValue()); + case T_double: return Constant.fromValue(left.doubleValue() >= right.doubleValue()); + case T_byte: return Constant.fromValue(left.doubleValue() >= right.byteValue()); + case T_short: return Constant.fromValue(left.doubleValue() >= right.shortValue()); + case T_int: return Constant.fromValue(left.doubleValue() >= right.intValue()); + case T_long: return Constant.fromValue(left.doubleValue() >= right.longValue()); + } + break; + case T_byte : + switch (rightId){ + case T_char : return Constant.fromValue(left.byteValue() >= right.charValue()); + case T_float: return Constant.fromValue(left.byteValue() >= right.floatValue()); + case T_double: return Constant.fromValue(left.byteValue() >= right.doubleValue()); + case T_byte: return Constant.fromValue(left.byteValue() >= right.byteValue()); + case T_short: return Constant.fromValue(left.byteValue() >= right.shortValue()); + case T_int: return Constant.fromValue(left.byteValue() >= right.intValue()); + case T_long: return Constant.fromValue(left.byteValue() >= right.longValue()); + } + break; + case T_short : + switch (rightId){ + case T_char : return Constant.fromValue(left.shortValue() >= right.charValue()); + case T_float: return Constant.fromValue(left.shortValue() >= right.floatValue()); + case T_double: return Constant.fromValue(left.shortValue() >= right.doubleValue()); + case T_byte: return Constant.fromValue(left.shortValue() >= right.byteValue()); + case T_short: return Constant.fromValue(left.shortValue() >= right.shortValue()); + case T_int: return Constant.fromValue(left.shortValue() >= right.intValue()); + case T_long: return Constant.fromValue(left.shortValue() >= right.longValue()); + } + break; + case T_int : + switch (rightId){ + case T_char : return Constant.fromValue(left.intValue() >= right.charValue()); + case T_float: return Constant.fromValue(left.intValue() >= right.floatValue()); + case T_double: return Constant.fromValue(left.intValue() >= right.doubleValue()); + case T_byte: return Constant.fromValue(left.intValue() >= right.byteValue()); + case T_short: return Constant.fromValue(left.intValue() >= right.shortValue()); + case T_int: return Constant.fromValue(left.intValue() >= right.intValue()); + case T_long: return Constant.fromValue(left.intValue() >= right.longValue()); + } + break; + case T_long : + switch (rightId){ + case T_char : return Constant.fromValue(left.longValue() >= right.charValue()); + case T_float: return Constant.fromValue(left.longValue() >= right.floatValue()); + case T_double: return Constant.fromValue(left.longValue() >= right.doubleValue()); + case T_byte: return Constant.fromValue(left.longValue() >= right.byteValue()); + case T_short: return Constant.fromValue(left.longValue() >= right.shortValue()); + case T_int: return Constant.fromValue(left.longValue() >= right.intValue()); + case T_long: return Constant.fromValue(left.longValue() >= right.longValue()); + } + + } + + return NotAConstant; + } + + public static final Constant computeConstantOperationLEFT_SHIFT(Constant left, int leftId, int operator, Constant right, int rightId) { + + switch (leftId){ + case T_char : + switch (rightId){ + case T_char : return Constant.fromValue(left.charValue() << right.charValue()); + case T_byte: return Constant.fromValue(left.charValue() << right.byteValue()); + case T_short: return Constant.fromValue(left.charValue() << right.shortValue()); + case T_int: return Constant.fromValue(left.charValue() << right.intValue()); + case T_long: return Constant.fromValue(left.charValue() << right.longValue()); + } + break; + case T_byte : + switch (rightId){ + case T_char : return Constant.fromValue(left.byteValue() << right.charValue()); + case T_byte: return Constant.fromValue(left.byteValue() << right.byteValue()); + case T_short: return Constant.fromValue(left.byteValue() << right.shortValue()); + case T_int: return Constant.fromValue(left.byteValue() << right.intValue()); + case T_long: return Constant.fromValue(left.byteValue() << right.longValue()); + } + break; + case T_short : + switch (rightId){ + case T_char : return Constant.fromValue(left.shortValue() << right.charValue()); + case T_byte: return Constant.fromValue(left.shortValue() << right.byteValue()); + case T_short: return Constant.fromValue(left.shortValue() << right.shortValue()); + case T_int: return Constant.fromValue(left.shortValue() << right.intValue()); + case T_long: return Constant.fromValue(left.shortValue() << right.longValue()); + } + break; + case T_int : + switch (rightId){ + case T_char : return Constant.fromValue(left.intValue() << right.charValue()); + case T_byte: return Constant.fromValue(left.intValue() << right.byteValue()); + case T_short: return Constant.fromValue(left.intValue() << right.shortValue()); + case T_int: return Constant.fromValue(left.intValue() << right.intValue()); + case T_long: return Constant.fromValue(left.intValue() << right.longValue()); + } + break; + case T_long : + switch (rightId){ + case T_char : return Constant.fromValue(left.longValue() << right.charValue()); + case T_byte: return Constant.fromValue(left.longValue() << right.byteValue()); + case T_short: return Constant.fromValue(left.longValue() << right.shortValue()); + case T_int: return Constant.fromValue(left.longValue() << right.intValue()); + case T_long: return Constant.fromValue(left.longValue() << right.longValue()); + } + + } + + return NotAConstant; + } + + public static final Constant computeConstantOperationLESS(Constant left, int leftId, int operator, Constant right, int rightId) { + + switch (leftId){ + case T_char : + switch (rightId){ + case T_char : return Constant.fromValue(left.charValue() < right.charValue()); + case T_float: return Constant.fromValue(left.charValue() < right.floatValue()); + case T_double: return Constant.fromValue(left.charValue() < right.doubleValue()); + case T_byte: return Constant.fromValue(left.charValue() < right.byteValue()); + case T_short: return Constant.fromValue(left.charValue() < right.shortValue()); + case T_int: return Constant.fromValue(left.charValue() < right.intValue()); + case T_long: return Constant.fromValue(left.charValue() < right.longValue()); + } + break; + case T_float : + switch (rightId){ + case T_char : return Constant.fromValue(left.floatValue() < right.charValue()); + case T_float: return Constant.fromValue(left.floatValue() < right.floatValue()); + case T_double: return Constant.fromValue(left.floatValue() < right.doubleValue()); + case T_byte: return Constant.fromValue(left.floatValue() < right.byteValue()); + case T_short: return Constant.fromValue(left.floatValue() < right.shortValue()); + case T_int: return Constant.fromValue(left.floatValue() < right.intValue()); + case T_long: return Constant.fromValue(left.floatValue() < right.longValue()); + } + break; + case T_double : + switch (rightId){ + case T_char : return Constant.fromValue(left.doubleValue() < right.charValue()); + case T_float: return Constant.fromValue(left.doubleValue() < right.floatValue()); + case T_double: return Constant.fromValue(left.doubleValue() < right.doubleValue()); + case T_byte: return Constant.fromValue(left.doubleValue() < right.byteValue()); + case T_short: return Constant.fromValue(left.doubleValue() < right.shortValue()); + case T_int: return Constant.fromValue(left.doubleValue() < right.intValue()); + case T_long: return Constant.fromValue(left.doubleValue() < right.longValue()); + } + break; + case T_byte : + switch (rightId){ + case T_char : return Constant.fromValue(left.byteValue() < right.charValue()); + case T_float: return Constant.fromValue(left.byteValue() < right.floatValue()); + case T_double: return Constant.fromValue(left.byteValue() < right.doubleValue()); + case T_byte: return Constant.fromValue(left.byteValue() < right.byteValue()); + case T_short: return Constant.fromValue(left.byteValue() < right.shortValue()); + case T_int: return Constant.fromValue(left.byteValue() < right.intValue()); + case T_long: return Constant.fromValue(left.byteValue() < right.longValue()); + } + break; + case T_short : + switch (rightId){ + case T_char : return Constant.fromValue(left.shortValue() < right.charValue()); + case T_float: return Constant.fromValue(left.shortValue() < right.floatValue()); + case T_double: return Constant.fromValue(left.shortValue() < right.doubleValue()); + case T_byte: return Constant.fromValue(left.shortValue() < right.byteValue()); + case T_short: return Constant.fromValue(left.shortValue() < right.shortValue()); + case T_int: return Constant.fromValue(left.shortValue() < right.intValue()); + case T_long: return Constant.fromValue(left.shortValue() < right.longValue()); + } + break; + case T_int : + switch (rightId){ + case T_char : return Constant.fromValue(left.intValue() < right.charValue()); + case T_float: return Constant.fromValue(left.intValue() < right.floatValue()); + case T_double: return Constant.fromValue(left.intValue() < right.doubleValue()); + case T_byte: return Constant.fromValue(left.intValue() < right.byteValue()); + case T_short: return Constant.fromValue(left.intValue() < right.shortValue()); + case T_int: return Constant.fromValue(left.intValue() < right.intValue()); + case T_long: return Constant.fromValue(left.intValue() < right.longValue()); + } + break; + case T_long : + switch (rightId){ + case T_char : return Constant.fromValue(left.longValue() < right.charValue()); + case T_float: return Constant.fromValue(left.longValue() < right.floatValue()); + case T_double: return Constant.fromValue(left.longValue() < right.doubleValue()); + case T_byte: return Constant.fromValue(left.longValue() < right.byteValue()); + case T_short: return Constant.fromValue(left.longValue() < right.shortValue()); + case T_int: return Constant.fromValue(left.longValue() < right.intValue()); + case T_long: return Constant.fromValue(left.longValue() < right.longValue()); + } + + } + + return NotAConstant; + } + + public static final Constant computeConstantOperationLESS_EQUAL(Constant left, int leftId, int operator, Constant right, int rightId) { + + switch (leftId){ + case T_char : + switch (rightId){ + case T_char : return Constant.fromValue(left.charValue() <= right.charValue()); + case T_float: return Constant.fromValue(left.charValue() <= right.floatValue()); + case T_double: return Constant.fromValue(left.charValue() <= right.doubleValue()); + case T_byte: return Constant.fromValue(left.charValue() <= right.byteValue()); + case T_short: return Constant.fromValue(left.charValue() <= right.shortValue()); + case T_int: return Constant.fromValue(left.charValue() <= right.intValue()); + case T_long: return Constant.fromValue(left.charValue() <= right.longValue()); + } + break; + case T_float : + switch (rightId){ + case T_char : return Constant.fromValue(left.floatValue() <= right.charValue()); + case T_float: return Constant.fromValue(left.floatValue() <= right.floatValue()); + case T_double: return Constant.fromValue(left.floatValue() <= right.doubleValue()); + case T_byte: return Constant.fromValue(left.floatValue() <= right.byteValue()); + case T_short: return Constant.fromValue(left.floatValue() <= right.shortValue()); + case T_int: return Constant.fromValue(left.floatValue() <= right.intValue()); + case T_long: return Constant.fromValue(left.floatValue() <= right.longValue()); + } + break; + case T_double : + switch (rightId){ + case T_char : return Constant.fromValue(left.doubleValue() <= right.charValue()); + case T_float: return Constant.fromValue(left.doubleValue() <= right.floatValue()); + case T_double: return Constant.fromValue(left.doubleValue() <= right.doubleValue()); + case T_byte: return Constant.fromValue(left.doubleValue() <= right.byteValue()); + case T_short: return Constant.fromValue(left.doubleValue() <= right.shortValue()); + case T_int: return Constant.fromValue(left.doubleValue() <= right.intValue()); + case T_long: return Constant.fromValue(left.doubleValue() <= right.longValue()); + } + break; + case T_byte : + switch (rightId){ + case T_char : return Constant.fromValue(left.byteValue() <= right.charValue()); + case T_float: return Constant.fromValue(left.byteValue() <= right.floatValue()); + case T_double: return Constant.fromValue(left.byteValue() <= right.doubleValue()); + case T_byte: return Constant.fromValue(left.byteValue() <= right.byteValue()); + case T_short: return Constant.fromValue(left.byteValue() <= right.shortValue()); + case T_int: return Constant.fromValue(left.byteValue() <= right.intValue()); + case T_long: return Constant.fromValue(left.byteValue() <= right.longValue()); + } + break; + case T_short : + switch (rightId){ + case T_char : return Constant.fromValue(left.shortValue() <= right.charValue()); + case T_float: return Constant.fromValue(left.shortValue() <= right.floatValue()); + case T_double: return Constant.fromValue(left.shortValue() <= right.doubleValue()); + case T_byte: return Constant.fromValue(left.shortValue() <= right.byteValue()); + case T_short: return Constant.fromValue(left.shortValue() <= right.shortValue()); + case T_int: return Constant.fromValue(left.shortValue() <= right.intValue()); + case T_long: return Constant.fromValue(left.shortValue() <= right.longValue()); + } + break; + case T_int : + switch (rightId){ + case T_char : return Constant.fromValue(left.intValue() <= right.charValue()); + case T_float: return Constant.fromValue(left.intValue() <= right.floatValue()); + case T_double: return Constant.fromValue(left.intValue() <= right.doubleValue()); + case T_byte: return Constant.fromValue(left.intValue() <= right.byteValue()); + case T_short: return Constant.fromValue(left.intValue() <= right.shortValue()); + case T_int: return Constant.fromValue(left.intValue() <= right.intValue()); + case T_long: return Constant.fromValue(left.intValue() <= right.longValue()); + } + break; + case T_long : + switch (rightId){ + case T_char : return Constant.fromValue(left.longValue() <= right.charValue()); + case T_float: return Constant.fromValue(left.longValue() <= right.floatValue()); + case T_double: return Constant.fromValue(left.longValue() <= right.doubleValue()); + case T_byte: return Constant.fromValue(left.longValue() <= right.byteValue()); + case T_short: return Constant.fromValue(left.longValue() <= right.shortValue()); + case T_int: return Constant.fromValue(left.longValue() <= right.intValue()); + case T_long: return Constant.fromValue(left.longValue() <= right.longValue()); + } + } + + return NotAConstant; + } + + public static final Constant computeConstantOperationMINUS(Constant left, int leftId, int operator, Constant right, int rightId) { + + switch (leftId){ + case T_char : + switch (rightId){ + case T_char : return Constant.fromValue(left.charValue() - right.charValue()); + case T_float: return Constant.fromValue(left.charValue() - right.floatValue()); + case T_double: return Constant.fromValue(left.charValue() - right.doubleValue()); + case T_byte: return Constant.fromValue(left.charValue() - right.byteValue()); + case T_short: return Constant.fromValue(left.charValue() - right.shortValue()); + case T_int: return Constant.fromValue(left.charValue() - right.intValue()); + case T_long: return Constant.fromValue(left.charValue() - right.longValue()); + } + break; + case T_float : + switch (rightId){ + case T_char : return Constant.fromValue(left.floatValue() - right.charValue()); + case T_float: return Constant.fromValue(left.floatValue() - right.floatValue()); + case T_double: return Constant.fromValue(left.floatValue() - right.doubleValue()); + case T_byte: return Constant.fromValue(left.floatValue() - right.byteValue()); + case T_short: return Constant.fromValue(left.floatValue() - right.shortValue()); + case T_int: return Constant.fromValue(left.floatValue() - right.intValue()); + case T_long: return Constant.fromValue(left.floatValue() - right.longValue()); + } + break; + case T_double : + switch (rightId){ + case T_char : return Constant.fromValue(left.doubleValue() - right.charValue()); + case T_float: return Constant.fromValue(left.doubleValue() - right.floatValue()); + case T_double: return Constant.fromValue(left.doubleValue() - right.doubleValue()); + case T_byte: return Constant.fromValue(left.doubleValue() - right.byteValue()); + case T_short: return Constant.fromValue(left.doubleValue() - right.shortValue()); + case T_int: return Constant.fromValue(left.doubleValue() - right.intValue()); + case T_long: return Constant.fromValue(left.doubleValue() - right.longValue()); + } + break; + case T_byte : + switch (rightId){ + case T_char : return Constant.fromValue(left.byteValue() - right.charValue()); + case T_float: return Constant.fromValue(left.byteValue() - right.floatValue()); + case T_double: return Constant.fromValue(left.byteValue() - right.doubleValue()); + case T_byte: return Constant.fromValue(left.byteValue() - right.byteValue()); + case T_short: return Constant.fromValue(left.byteValue() - right.shortValue()); + case T_int: return Constant.fromValue(left.byteValue() - right.intValue()); + case T_long: return Constant.fromValue(left.byteValue() - right.longValue()); + } + break; + case T_short : + switch (rightId){ + case T_char : return Constant.fromValue(left.shortValue() - right.charValue()); + case T_float: return Constant.fromValue(left.shortValue() - right.floatValue()); + case T_double: return Constant.fromValue(left.shortValue() - right.doubleValue()); + case T_byte: return Constant.fromValue(left.shortValue() - right.byteValue()); + case T_short: return Constant.fromValue(left.shortValue() - right.shortValue()); + case T_int: return Constant.fromValue(left.shortValue() - right.intValue()); + case T_long: return Constant.fromValue(left.shortValue() - right.longValue()); + } + break; + case T_int : + switch (rightId){ + case T_char : return Constant.fromValue(left.intValue() - right.charValue()); + case T_float: return Constant.fromValue(left.intValue() - right.floatValue()); + case T_double: return Constant.fromValue(left.intValue() - right.doubleValue()); + case T_byte: return Constant.fromValue(left.intValue() - right.byteValue()); + case T_short: return Constant.fromValue(left.intValue() - right.shortValue()); + case T_int: return Constant.fromValue(left.intValue() - right.intValue()); + case T_long: return Constant.fromValue(left.intValue() - right.longValue()); + } + break; + case T_long : + switch (rightId){ + case T_char : return Constant.fromValue(left.longValue() - right.charValue()); + case T_float: return Constant.fromValue(left.longValue() - right.floatValue()); + case T_double: return Constant.fromValue(left.longValue() - right.doubleValue()); + case T_byte: return Constant.fromValue(left.longValue() - right.byteValue()); + case T_short: return Constant.fromValue(left.longValue() - right.shortValue()); + case T_int: return Constant.fromValue(left.longValue() - right.intValue()); + case T_long: return Constant.fromValue(left.longValue() - right.longValue()); + } + + } + + return NotAConstant; + } + + public static final Constant computeConstantOperationMULTIPLY(Constant left, int leftId, int operator, Constant right, int rightId) { + + switch (leftId){ + case T_char : + switch (rightId){ + case T_char : return Constant.fromValue(left.charValue() * right.charValue()); + case T_float: return Constant.fromValue(left.charValue() * right.floatValue()); + case T_double: return Constant.fromValue(left.charValue() * right.doubleValue()); + case T_byte: return Constant.fromValue(left.charValue() * right.byteValue()); + case T_short: return Constant.fromValue(left.charValue() * right.shortValue()); + case T_int: return Constant.fromValue(left.charValue() * right.intValue()); + case T_long: return Constant.fromValue(left.charValue() * right.longValue()); + } + break; + case T_float : + switch (rightId){ + case T_char : return Constant.fromValue(left.floatValue() * right.charValue()); + case T_float: return Constant.fromValue(left.floatValue() * right.floatValue()); + case T_double: return Constant.fromValue(left.floatValue() * right.doubleValue()); + case T_byte: return Constant.fromValue(left.floatValue() * right.byteValue()); + case T_short: return Constant.fromValue(left.floatValue() * right.shortValue()); + case T_int: return Constant.fromValue(left.floatValue() * right.intValue()); + case T_long: return Constant.fromValue(left.floatValue() * right.longValue()); + } + break; + case T_double : + switch (rightId){ + case T_char : return Constant.fromValue(left.doubleValue() * right.charValue()); + case T_float: return Constant.fromValue(left.doubleValue() * right.floatValue()); + case T_double: return Constant.fromValue(left.doubleValue() * right.doubleValue()); + case T_byte: return Constant.fromValue(left.doubleValue() * right.byteValue()); + case T_short: return Constant.fromValue(left.doubleValue() * right.shortValue()); + case T_int: return Constant.fromValue(left.doubleValue() * right.intValue()); + case T_long: return Constant.fromValue(left.doubleValue() * right.longValue()); + } + break; + case T_byte : + switch (rightId){ + case T_char : return Constant.fromValue(left.byteValue() * right.charValue()); + case T_float: return Constant.fromValue(left.byteValue() * right.floatValue()); + case T_double: return Constant.fromValue(left.byteValue() * right.doubleValue()); + case T_byte: return Constant.fromValue(left.byteValue() * right.byteValue()); + case T_short: return Constant.fromValue(left.byteValue() * right.shortValue()); + case T_int: return Constant.fromValue(left.byteValue() * right.intValue()); + case T_long: return Constant.fromValue(left.byteValue() * right.longValue()); + } + break; + case T_short : + switch (rightId){ + case T_char : return Constant.fromValue(left.shortValue() * right.charValue()); + case T_float: return Constant.fromValue(left.shortValue() * right.floatValue()); + case T_double: return Constant.fromValue(left.shortValue() * right.doubleValue()); + case T_byte: return Constant.fromValue(left.shortValue() * right.byteValue()); + case T_short: return Constant.fromValue(left.shortValue() * right.shortValue()); + case T_int: return Constant.fromValue(left.shortValue() * right.intValue()); + case T_long: return Constant.fromValue(left.shortValue() * right.longValue()); + } + break; + case T_int : + switch (rightId){ + case T_char : return Constant.fromValue(left.intValue() * right.charValue()); + case T_float: return Constant.fromValue(left.intValue() * right.floatValue()); + case T_double: return Constant.fromValue(left.intValue() * right.doubleValue()); + case T_byte: return Constant.fromValue(left.intValue() * right.byteValue()); + case T_short: return Constant.fromValue(left.intValue() * right.shortValue()); + case T_int: return Constant.fromValue(left.intValue() * right.intValue()); + case T_long: return Constant.fromValue(left.intValue() * right.longValue()); + } + break; + case T_long : + switch (rightId){ + case T_char : return Constant.fromValue(left.longValue() * right.charValue()); + case T_float: return Constant.fromValue(left.longValue() * right.floatValue()); + case T_double: return Constant.fromValue(left.longValue() * right.doubleValue()); + case T_byte: return Constant.fromValue(left.longValue() * right.byteValue()); + case T_short: return Constant.fromValue(left.longValue() * right.shortValue()); + case T_int: return Constant.fromValue(left.longValue() * right.intValue()); + case T_long: return Constant.fromValue(left.longValue() * right.longValue()); + } + } + + return NotAConstant; + } + + public static final Constant computeConstantOperationOR(Constant left, int leftId, int operator, Constant right, int rightId) { + + switch (leftId){ + case T_boolean : return Constant.fromValue(left.booleanValue() | right.booleanValue()); + case T_char : + switch (rightId){ + case T_char : return Constant.fromValue(left.charValue() | right.charValue()); + case T_byte: return Constant.fromValue(left.charValue() | right.byteValue()); + case T_short: return Constant.fromValue(left.charValue() | right.shortValue()); + case T_int: return Constant.fromValue(left.charValue() | right.intValue()); + case T_long: return Constant.fromValue(left.charValue() | right.longValue()); + } + break; + case T_byte : + switch (rightId){ + case T_char : return Constant.fromValue(left.byteValue() | right.charValue()); + case T_byte: return Constant.fromValue(left.byteValue() | right.byteValue()); + case T_short: return Constant.fromValue(left.byteValue() | right.shortValue()); + case T_int: return Constant.fromValue(left.byteValue() | right.intValue()); + case T_long: return Constant.fromValue(left.byteValue() | right.longValue()); + } + break; + case T_short : + switch (rightId){ + case T_char : return Constant.fromValue(left.shortValue() | right.charValue()); + case T_byte: return Constant.fromValue(left.shortValue() | right.byteValue()); + case T_short: return Constant.fromValue(left.shortValue() | right.shortValue()); + case T_int: return Constant.fromValue(left.shortValue() | right.intValue()); + case T_long: return Constant.fromValue(left.shortValue() | right.longValue()); + } + break; + case T_int : + switch (rightId){ + case T_char : return Constant.fromValue(left.intValue() | right.charValue()); + case T_byte: return Constant.fromValue(left.intValue() | right.byteValue()); + case T_short: return Constant.fromValue(left.intValue() | right.shortValue()); + case T_int: return Constant.fromValue(left.intValue() | right.intValue()); + case T_long: return Constant.fromValue(left.intValue() | right.longValue()); + } + break; + case T_long : + switch (rightId){ + case T_char : return Constant.fromValue(left.longValue() | right.charValue()); + case T_byte: return Constant.fromValue(left.longValue() | right.byteValue()); + case T_short: return Constant.fromValue(left.longValue() | right.shortValue()); + case T_int: return Constant.fromValue(left.longValue() | right.intValue()); + case T_long: return Constant.fromValue(left.longValue() | right.longValue()); + } + + } + + return NotAConstant; + } + + public static final Constant computeConstantOperationOR_OR(Constant left, int leftId, int operator, Constant right, int rightId) { + + return Constant.fromValue(left.booleanValue() || right.booleanValue()); + } + + public static final Constant computeConstantOperationPLUS(Constant left, int leftId, int operator, Constant right, int rightId) { + + switch (leftId){ + case T_Object : + if (rightId == T_String) { + return Constant.fromValue(left.stringValue() + right.stringValue()); + } + case T_boolean : + if (rightId == T_String) { + return Constant.fromValue(left.stringValue() + right.stringValue()); + } + break; + case T_char : + switch (rightId){ + case T_char : return Constant.fromValue(left.charValue() + right.charValue()); + case T_float: return Constant.fromValue(left.charValue() + right.floatValue()); + case T_double: return Constant.fromValue(left.charValue() + right.doubleValue()); + case T_byte: return Constant.fromValue(left.charValue() + right.byteValue()); + case T_short: return Constant.fromValue(left.charValue() + right.shortValue()); + case T_int: return Constant.fromValue(left.charValue() + right.intValue()); + case T_long: return Constant.fromValue(left.charValue() + right.longValue()); + case T_String: return Constant.fromValue(left.stringValue() + right.stringValue()); + } + break; + case T_float : + switch (rightId){ + case T_char : return Constant.fromValue(left.floatValue() + right.charValue()); + case T_float: return Constant.fromValue(left.floatValue() + right.floatValue()); + case T_double: return Constant.fromValue(left.floatValue() + right.doubleValue()); + case T_byte: return Constant.fromValue(left.floatValue() + right.byteValue()); + case T_short: return Constant.fromValue(left.floatValue() + right.shortValue()); + case T_int: return Constant.fromValue(left.floatValue() + right.intValue()); + case T_long: return Constant.fromValue(left.floatValue() + right.longValue()); + case T_String: return Constant.fromValue(left.stringValue() + right.stringValue()); + } + break; + case T_double : + switch (rightId){ + case T_char : return Constant.fromValue(left.doubleValue() + right.charValue()); + case T_float: return Constant.fromValue(left.doubleValue() + right.floatValue()); + case T_double: return Constant.fromValue(left.doubleValue() + right.doubleValue()); + case T_byte: return Constant.fromValue(left.doubleValue() + right.byteValue()); + case T_short: return Constant.fromValue(left.doubleValue() + right.shortValue()); + case T_int: return Constant.fromValue(left.doubleValue() + right.intValue()); + case T_long: return Constant.fromValue(left.doubleValue() + right.longValue()); + case T_String: return Constant.fromValue(left.stringValue() + right.stringValue()); + } + break; + case T_byte : + switch (rightId){ + case T_char : return Constant.fromValue(left.byteValue() + right.charValue()); + case T_float: return Constant.fromValue(left.byteValue() + right.floatValue()); + case T_double: return Constant.fromValue(left.byteValue() + right.doubleValue()); + case T_byte: return Constant.fromValue(left.byteValue() + right.byteValue()); + case T_short: return Constant.fromValue(left.byteValue() + right.shortValue()); + case T_int: return Constant.fromValue(left.byteValue() + right.intValue()); + case T_long: return Constant.fromValue(left.byteValue() + right.longValue()); + case T_String: return Constant.fromValue(left.stringValue() + right.stringValue()); + } + + break; + case T_short : + switch (rightId){ + case T_char : return Constant.fromValue(left.shortValue() + right.charValue()); + case T_float: return Constant.fromValue(left.shortValue() + right.floatValue()); + case T_double: return Constant.fromValue(left.shortValue() + right.doubleValue()); + case T_byte: return Constant.fromValue(left.shortValue() + right.byteValue()); + case T_short: return Constant.fromValue(left.shortValue() + right.shortValue()); + case T_int: return Constant.fromValue(left.shortValue() + right.intValue()); + case T_long: return Constant.fromValue(left.shortValue() + right.longValue()); + case T_String: return Constant.fromValue(left.stringValue() + right.stringValue()); + } + break; + case T_int : + switch (rightId){ + case T_char : return Constant.fromValue(left.intValue() + right.charValue()); + case T_float: return Constant.fromValue(left.intValue() + right.floatValue()); + case T_double: return Constant.fromValue(left.intValue() + right.doubleValue()); + case T_byte: return Constant.fromValue(left.intValue() + right.byteValue()); + case T_short: return Constant.fromValue(left.intValue() + right.shortValue()); + case T_int: return Constant.fromValue(left.intValue() + right.intValue()); + case T_long: return Constant.fromValue(left.intValue() + right.longValue()); + case T_String: return Constant.fromValue(left.stringValue() + right.stringValue()); + } + break; + case T_long : + switch (rightId){ + case T_char : return Constant.fromValue(left.longValue() + right.charValue()); + case T_float: return Constant.fromValue(left.longValue() + right.floatValue()); + case T_double: return Constant.fromValue(left.longValue() + right.doubleValue()); + case T_byte: return Constant.fromValue(left.longValue() + right.byteValue()); + case T_short: return Constant.fromValue(left.longValue() + right.shortValue()); + case T_int: return Constant.fromValue(left.longValue() + right.intValue()); + case T_long: return Constant.fromValue(left.longValue() + right.longValue()); + case T_String: return Constant.fromValue(left.stringValue() + right.stringValue()); + } + break; + case T_String : + switch (rightId){ + case T_char : return Constant.fromValue(left.stringValue() + right.stringValue()); + case T_float: return Constant.fromValue(left.stringValue() + right.stringValue()); + case T_double: return Constant.fromValue(left.stringValue() + right.stringValue()); + case T_byte: return Constant.fromValue(left.stringValue() + right.stringValue()); + case T_short: return Constant.fromValue(left.stringValue() + right.stringValue()); + case T_int: return Constant.fromValue(left.stringValue() + right.stringValue()); + case T_long: return Constant.fromValue(left.stringValue() + right.stringValue()); + case T_String: return Constant.fromValue(left.stringValue() + right.stringValue()); + case T_boolean: return Constant.fromValue(left.stringValue() + right.stringValue()); + } + break; + case T_null : + switch (rightId){ + case T_char : return Constant.fromValue(left.stringValue() + right.stringValue()); + case T_float: return Constant.fromValue(left.stringValue() + right.stringValue()); + case T_double: return Constant.fromValue(left.stringValue() + right.stringValue()); + case T_byte: return Constant.fromValue(left.stringValue() + right.stringValue()); + case T_short: return Constant.fromValue(left.stringValue() + right.stringValue()); + case T_int: return Constant.fromValue(left.stringValue() + right.stringValue()); + case T_long: return Constant.fromValue(left.stringValue() + right.stringValue()); + case T_String: return Constant.fromValue(left.stringValue() + right.stringValue()); + } + + } + + return NotAConstant; + } + + public static final Constant computeConstantOperationREMAINDER(Constant left, int leftId, int operator, Constant right, int rightId) { + + switch (leftId){ + case T_char : + switch (rightId){ + case T_char : return Constant.fromValue(left.charValue() % right.charValue()); + case T_float: return Constant.fromValue(left.charValue() % right.floatValue()); + case T_double: return Constant.fromValue(left.charValue() % right.doubleValue()); + case T_byte: return Constant.fromValue(left.charValue() % right.byteValue()); + case T_short: return Constant.fromValue(left.charValue() % right.shortValue()); + case T_int: return Constant.fromValue(left.charValue() % right.intValue()); + case T_long: return Constant.fromValue(left.charValue() % right.longValue()); + } + break; + case T_float : + switch (rightId){ + case T_char : return Constant.fromValue(left.floatValue() % right.charValue()); + case T_float: return Constant.fromValue(left.floatValue() % right.floatValue()); + case T_double: return Constant.fromValue(left.floatValue() % right.doubleValue()); + case T_byte: return Constant.fromValue(left.floatValue() % right.byteValue()); + case T_short: return Constant.fromValue(left.floatValue() % right.shortValue()); + case T_int: return Constant.fromValue(left.floatValue() % right.intValue()); + case T_long: return Constant.fromValue(left.floatValue() % right.longValue()); + } + break; + case T_double : + switch (rightId){ + case T_char : return Constant.fromValue(left.doubleValue() % right.charValue()); + case T_float: return Constant.fromValue(left.doubleValue() % right.floatValue()); + case T_double: return Constant.fromValue(left.doubleValue() % right.doubleValue()); + case T_byte: return Constant.fromValue(left.doubleValue() % right.byteValue()); + case T_short: return Constant.fromValue(left.doubleValue() % right.shortValue()); + case T_int: return Constant.fromValue(left.doubleValue() % right.intValue()); + case T_long: return Constant.fromValue(left.doubleValue() % right.longValue()); + } + break; + case T_byte : + switch (rightId){ + case T_char : return Constant.fromValue(left.byteValue() % right.charValue()); + case T_float: return Constant.fromValue(left.byteValue() % right.floatValue()); + case T_double: return Constant.fromValue(left.byteValue() % right.doubleValue()); + case T_byte: return Constant.fromValue(left.byteValue() % right.byteValue()); + case T_short: return Constant.fromValue(left.byteValue() % right.shortValue()); + case T_int: return Constant.fromValue(left.byteValue() % right.intValue()); + case T_long: return Constant.fromValue(left.byteValue() % right.longValue()); + } + break; + case T_short : + switch (rightId){ + case T_char : return Constant.fromValue(left.shortValue() % right.charValue()); + case T_float: return Constant.fromValue(left.shortValue() % right.floatValue()); + case T_double: return Constant.fromValue(left.shortValue() % right.doubleValue()); + case T_byte: return Constant.fromValue(left.shortValue() % right.byteValue()); + case T_short: return Constant.fromValue(left.shortValue() % right.shortValue()); + case T_int: return Constant.fromValue(left.shortValue() % right.intValue()); + case T_long: return Constant.fromValue(left.shortValue() % right.longValue()); + } + break; + case T_int : + switch (rightId){ + case T_char : return Constant.fromValue(left.intValue() % right.charValue()); + case T_float: return Constant.fromValue(left.intValue() % right.floatValue()); + case T_double: return Constant.fromValue(left.intValue() % right.doubleValue()); + case T_byte: return Constant.fromValue(left.intValue() % right.byteValue()); + case T_short: return Constant.fromValue(left.intValue() % right.shortValue()); + case T_int: return Constant.fromValue(left.intValue() % right.intValue()); + case T_long: return Constant.fromValue(left.intValue() % right.longValue()); + } + break; + case T_long : + switch (rightId){ + case T_char : return Constant.fromValue(left.longValue() % right.charValue()); + case T_float: return Constant.fromValue(left.longValue() % right.floatValue()); + case T_double: return Constant.fromValue(left.longValue() % right.doubleValue()); + case T_byte: return Constant.fromValue(left.longValue() % right.byteValue()); + case T_short: return Constant.fromValue(left.longValue() % right.shortValue()); + case T_int: return Constant.fromValue(left.longValue() % right.intValue()); + case T_long: return Constant.fromValue(left.longValue() % right.longValue()); + } + + } + + return NotAConstant; + } + + public static final Constant computeConstantOperationRIGHT_SHIFT(Constant left, int leftId, int operator, Constant right, int rightId) { + + switch (leftId){ + case T_char : + switch (rightId){ + case T_char : return Constant.fromValue(left.charValue() >> right.charValue()); + case T_byte: return Constant.fromValue(left.charValue() >> right.byteValue()); + case T_short: return Constant.fromValue(left.charValue() >> right.shortValue()); + case T_int: return Constant.fromValue(left.charValue() >> right.intValue()); + case T_long: return Constant.fromValue(left.charValue() >> right.longValue()); + } + break; + case T_byte : + switch (rightId){ + case T_char : return Constant.fromValue(left.byteValue() >> right.charValue()); + case T_byte: return Constant.fromValue(left.byteValue() >> right.byteValue()); + case T_short: return Constant.fromValue(left.byteValue() >> right.shortValue()); + case T_int: return Constant.fromValue(left.byteValue() >> right.intValue()); + case T_long: return Constant.fromValue(left.byteValue() >> right.longValue()); + } + break; + case T_short : + switch (rightId){ + case T_char : return Constant.fromValue(left.shortValue() >> right.charValue()); + case T_byte: return Constant.fromValue(left.shortValue() >> right.byteValue()); + case T_short: return Constant.fromValue(left.shortValue() >> right.shortValue()); + case T_int: return Constant.fromValue(left.shortValue() >> right.intValue()); + case T_long: return Constant.fromValue(left.shortValue() >> right.longValue()); + } + break; + case T_int : + switch (rightId){ + case T_char : return Constant.fromValue(left.intValue() >> right.charValue()); + case T_byte: return Constant.fromValue(left.intValue() >> right.byteValue()); + case T_short: return Constant.fromValue(left.intValue() >> right.shortValue()); + case T_int: return Constant.fromValue(left.intValue() >> right.intValue()); + case T_long: return Constant.fromValue(left.intValue() >> right.longValue()); + } + break; + case T_long : + switch (rightId){ + case T_char : return Constant.fromValue(left.longValue() >> right.charValue()); + case T_byte: return Constant.fromValue(left.longValue() >> right.byteValue()); + case T_short: return Constant.fromValue(left.longValue() >> right.shortValue()); + case T_int: return Constant.fromValue(left.longValue() >> right.intValue()); + case T_long: return Constant.fromValue(left.longValue() >> right.longValue()); + } + + } + + return NotAConstant; + } + + public static final Constant computeConstantOperationUNSIGNED_RIGHT_SHIFT(Constant left, int leftId, int operator, Constant right, int rightId) { + + switch (leftId){ + case T_char : + switch (rightId){ + case T_char : return Constant.fromValue(left.charValue() >>> right.charValue()); + case T_byte: return Constant.fromValue(left.charValue() >>> right.byteValue()); + case T_short: return Constant.fromValue(left.charValue() >>> right.shortValue()); + case T_int: return Constant.fromValue(left.charValue() >>> right.intValue()); + case T_long: return Constant.fromValue(left.charValue() >>> right.longValue()); + } + break; + case T_byte : + switch (rightId){ + case T_char : return Constant.fromValue(left.byteValue() >>> right.charValue()); + case T_byte: return Constant.fromValue(left.byteValue() >>> right.byteValue()); + case T_short: return Constant.fromValue(left.byteValue() >>> right.shortValue()); + case T_int: return Constant.fromValue(left.byteValue() >>> right.intValue()); + case T_long: return Constant.fromValue(left.byteValue() >>> right.longValue()); + } + break; + case T_short : + switch (rightId){ + case T_char : return Constant.fromValue(left.shortValue() >>> right.charValue()); + case T_byte: return Constant.fromValue(left.shortValue() >>> right.byteValue()); + case T_short: return Constant.fromValue(left.shortValue() >>> right.shortValue()); + case T_int: return Constant.fromValue(left.shortValue() >>> right.intValue()); + case T_long: return Constant.fromValue(left.shortValue() >>> right.longValue()); + } + break; + case T_int : + switch (rightId){ + case T_char : return Constant.fromValue(left.intValue() >>> right.charValue()); + case T_byte: return Constant.fromValue(left.intValue() >>> right.byteValue()); + case T_short: return Constant.fromValue(left.intValue() >>> right.shortValue()); + case T_int: return Constant.fromValue(left.intValue() >>> right.intValue()); + case T_long: return Constant.fromValue(left.intValue() >>> right.longValue()); + } + break; + case T_long : + switch (rightId){ + case T_char : return Constant.fromValue(left.longValue() >>> right.charValue()); + case T_byte: return Constant.fromValue(left.longValue() >>> right.byteValue()); + case T_short: return Constant.fromValue(left.longValue() >>> right.shortValue()); + case T_int: return Constant.fromValue(left.longValue() >>> right.intValue()); + case T_long: return Constant.fromValue(left.longValue() >>> right.longValue()); + } + + } + + return NotAConstant; + } + + public static final Constant computeConstantOperationXOR(Constant left, int leftId, int operator, Constant right, int rightId) { + + switch (leftId){ + case T_boolean : return Constant.fromValue(left.booleanValue() ^ right.booleanValue()); + case T_char : + switch (rightId){ + case T_char : return Constant.fromValue(left.charValue() ^ right.charValue()); + case T_byte: return Constant.fromValue(left.charValue() ^ right.byteValue()); + case T_short: return Constant.fromValue(left.charValue() ^ right.shortValue()); + case T_int: return Constant.fromValue(left.charValue() ^ right.intValue()); + case T_long: return Constant.fromValue(left.charValue() ^ right.longValue()); + } + break; + case T_byte : + switch (rightId){ + case T_char : return Constant.fromValue(left.byteValue() ^ right.charValue()); + case T_byte: return Constant.fromValue(left.byteValue() ^ right.byteValue()); + case T_short: return Constant.fromValue(left.byteValue() ^ right.shortValue()); + case T_int: return Constant.fromValue(left.byteValue() ^ right.intValue()); + case T_long: return Constant.fromValue(left.byteValue() ^ right.longValue()); + } + break; + case T_short : + switch (rightId){ + case T_char : return Constant.fromValue(left.shortValue() ^ right.charValue()); + case T_byte: return Constant.fromValue(left.shortValue() ^ right.byteValue()); + case T_short: return Constant.fromValue(left.shortValue() ^ right.shortValue()); + case T_int: return Constant.fromValue(left.shortValue() ^ right.intValue()); + case T_long: return Constant.fromValue(left.shortValue() ^ right.longValue()); + } + break; + case T_int : + switch (rightId){ + case T_char : return Constant.fromValue(left.intValue() ^ right.charValue()); + case T_byte: return Constant.fromValue(left.intValue() ^ right.byteValue()); + case T_short: return Constant.fromValue(left.intValue() ^ right.shortValue()); + case T_int: return Constant.fromValue(left.intValue() ^ right.intValue()); + case T_long: return Constant.fromValue(left.intValue() ^ right.longValue()); + } + break; + case T_long : + switch (rightId){ + case T_char : return Constant.fromValue(left.longValue() ^ right.charValue()); + case T_byte: return Constant.fromValue(left.longValue() ^ right.byteValue()); + case T_short: return Constant.fromValue(left.longValue() ^ right.shortValue()); + case T_int: return Constant.fromValue(left.longValue() ^ right.intValue()); + case T_long: return Constant.fromValue(left.longValue() ^ right.longValue()); + } + } + + return NotAConstant; + } + + public double doubleValue() { + + throw new ShouldNotImplement(Util.bind("constant.cannotCastedInto",typeName(),"double")); //$NON-NLS-2$ //$NON-NLS-1$ + } + + public float floatValue() { + + throw new ShouldNotImplement(Util.bind("constant.cannotCastedInto",typeName(),"float")); //$NON-NLS-2$ //$NON-NLS-1$ + } + + public static Constant fromValue(byte value) { + + return new ByteConstant(value); + } + + public static Constant fromValue(char value) { + + return new CharConstant(value); + } + + public static Constant fromValue(double value) { + + return new DoubleConstant(value); + } + + public static Constant fromValue(float value) { + + return new FloatConstant(value); + } + + public static Constant fromValue(int value) { + + return new IntConstant(value); + } + + public static Constant fromValue(long value) { + + return new LongConstant(value); + } + + public static Constant fromValue(String value) { + + return new StringConstant(value); + } + + public static Constant fromValue(short value) { + + return new ShortConstant(value); + } + + public static Constant fromValue(boolean value) { + + return new BooleanConstant(value); + } + + public int intValue() { + + throw new ShouldNotImplement(Util.bind("constant.cannotCastedInto",typeName(),"int")); //$NON-NLS-2$ //$NON-NLS-1$ + } + + public long longValue() { + + throw new ShouldNotImplement(Util.bind("constant.cannotCastedInto",typeName(),"long")); //$NON-NLS-2$ //$NON-NLS-1$ + } + + public short shortValue() { + + throw new ShouldNotImplement(Util.bind("constant.cannotConvertedTo",typeName(),"short")); //$NON-NLS-2$ //$NON-NLS-1$ + } + + public String stringValue() { + + throw new ShouldNotImplement(Util.bind("constant.cannotConvertedTo",typeName(),"String")); //$NON-NLS-1$ //$NON-NLS-2$ + } + + public String toString(){ + + if (this == NotAConstant) return "(Constant) NotAConstant"; //$NON-NLS-1$ + return super.toString(); } + + public abstract int typeID(); + + public String typeName() { + switch (typeID()) { + case T_int : return "int"; //$NON-NLS-1$ + case T_byte : return "byte"; //$NON-NLS-1$ + case T_short : return "short"; //$NON-NLS-1$ + case T_char : return "char"; //$NON-NLS-1$ + case T_float : return "float"; //$NON-NLS-1$ + case T_double : return "double"; //$NON-NLS-1$ + case T_boolean : return "boolean"; //$NON-NLS-1$ + case T_long : return "long";//$NON-NLS-1$ + case T_String : return "java.lang.String"; //$NON-NLS-1$ + case T_null : return "null"; //$NON-NLS-1$ + default: return "unknown"; //$NON-NLS-1$ + } + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/impl/DoubleConstant.java b/src/java/org/eclipse/jdt/internal/compiler/impl/DoubleConstant.java new file mode 100644 index 0000000..ca72801 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/impl/DoubleConstant.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.impl; + +public class DoubleConstant extends Constant { + + double value; + + public DoubleConstant(double value) { + this.value = value; + } + + public byte byteValue() { + return (byte) value; + } + + public char charValue() { + return (char) value; + } + + public double doubleValue() { + return this.value; + } + + public float floatValue() { + return (float) value; + } + + public int intValue() { + return (int) value; + } + + public long longValue() { + return (long) value; + } + + public short shortValue() { + return (short) value; + } + + public String stringValue() { + String s = Double.toString(value); + if (s == null) return "null"; //$NON-NLS-1$ + return s; + } + + public String toString() { + if (this == NotAConstant) + return "(Constant) NotAConstant"; //$NON-NLS-1$ + return "(double)" + value; //$NON-NLS-1$ + } + + public int typeID() { + return T_double; + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/impl/FloatConstant.java b/src/java/org/eclipse/jdt/internal/compiler/impl/FloatConstant.java new file mode 100644 index 0000000..6caec4d --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/impl/FloatConstant.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.impl; + +public class FloatConstant extends Constant { + + float value; + + public FloatConstant(float value) { + this.value = value; + } + + public byte byteValue() { + return (byte) value; + } + + public char charValue() { + return (char) value; + } + + public double doubleValue() { + return value; // implicit cast to return type + } + + public float floatValue() { + return this.value; + } + + public int intValue() { + return (int) value; + } + + public long longValue() { + return (long) value; + } + + public short shortValue() { + return (short) value; + } + + public String stringValue() { + String s = Float.toString(value); + if (s == null) return "null"; //$NON-NLS-1$ + return s; + } + + public String toString() { + return "(float)" + value; //$NON-NLS-1$ + } + + public int typeID() { + return T_float; + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/impl/ITypeRequestor.java b/src/java/org/eclipse/jdt/internal/compiler/impl/ITypeRequestor.java new file mode 100644 index 0000000..52398d0 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/impl/ITypeRequestor.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.impl; + +import org.eclipse.jdt.internal.compiler.env.IBinaryType; +import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; +import org.eclipse.jdt.internal.compiler.env.ISourceType; +import org.eclipse.jdt.internal.compiler.lookup.PackageBinding; + +public interface ITypeRequestor { + + /** + * Accept the resolved binary form for the requested type. + */ + void accept(IBinaryType binaryType, PackageBinding packageBinding); + + /** + * Accept the requested type's compilation unit. + */ + void accept(ICompilationUnit unit); + + /** + * Accept the unresolved source forms for the requested type. + * Note that the multiple source forms can be answered, in case the target compilation unit + * contains multiple types. The first one is then guaranteed to be the one corresponding to the + * requested type. + */ + void accept(ISourceType[] sourceType, PackageBinding packageBinding); +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/impl/IntConstant.java b/src/java/org/eclipse/jdt/internal/compiler/impl/IntConstant.java new file mode 100644 index 0000000..8d54e90 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/impl/IntConstant.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.impl; + +public class IntConstant extends Constant { + + int value; + + public IntConstant(int value) { + this.value = value; + } + + public byte byteValue() { + return (byte) value; + } + + public char charValue() { + return (char) value; + } + + public double doubleValue() { + return value; // implicit cast to return type + } + + public float floatValue() { + return value; // implicit cast to return type + } + + public int intValue() { + return value; + } + + public long longValue() { + return value; // implicit cast to return type + } + + public short shortValue() { + return (short) value; + } + + public String stringValue() { + //spec 15.17.11 + String s = new Integer(value).toString(); + if (s == null) return "null"; //$NON-NLS-1$ + return s; + } + + public String toString() { + return "(int)" + value; //$NON-NLS-1$ + } + + public int typeID() { + return T_int; + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/impl/LongConstant.java b/src/java/org/eclipse/jdt/internal/compiler/impl/LongConstant.java new file mode 100644 index 0000000..c730665 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/impl/LongConstant.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.impl; + +public class LongConstant extends Constant { + long value; +public LongConstant(long value) { + this.value = value; +} +public byte byteValue() { + return (byte) value; +} +public char charValue() { + return (char) value; +} +public double doubleValue() { + return value; // implicit cast to return type +} +public float floatValue() { + return value; // implicit cast to return type +} +public int intValue() { + return (int) value; +} +public long longValue() { + return value; +} +public short shortValue() { + return (short) value; +} +public String stringValue() { + //spec 15.17.11 + + String s = new Long(value).toString() ; + if (s == null) return "null"; //$NON-NLS-1$ + return s; +} +public String toString(){ + + return "(long)" + value ; } //$NON-NLS-1$ +public int typeID() { + return T_long; +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/impl/ReferenceContext.java b/src/java/org/eclipse/jdt/internal/compiler/impl/ReferenceContext.java new file mode 100644 index 0000000..f645b0a --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/impl/ReferenceContext.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.impl; +/* + * Implementors are valid compilation contexts from which we can + * escape in case of error: + * For example: method, type or compilation unit. + */ + +import org.eclipse.jdt.core.compiler.IProblem; +import org.eclipse.jdt.internal.compiler.CompilationResult; + +public interface ReferenceContext { + void abort(int abortLevel, IProblem problem); + CompilationResult compilationResult(); + void tagAsHavingErrors(); + boolean hasErrors(); +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/impl/ShortConstant.java b/src/java/org/eclipse/jdt/internal/compiler/impl/ShortConstant.java new file mode 100644 index 0000000..0bad92d --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/impl/ShortConstant.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.impl; + +public class ShortConstant extends Constant { + short value; +public ShortConstant(short value) { + this.value = value; +} +public byte byteValue() { + return (byte) value; +} +public char charValue() { + return (char) value; +} +public double doubleValue() { + return value; // implicit cast to return type +} +public float floatValue() { + return value; // implicit cast to return type +} +public int intValue() { + return value; // implicit cast to return type +} +public long longValue() { + return value; // implicit cast to return type +} +public short shortValue() { + return value; +} +public String stringValue() { + //spec 15.17.11 + + String s = new Integer(value).toString() ; + if (s == null) return "null"; //$NON-NLS-1$ + return s; +} +public String toString(){ + + return "(short)" + value ; } //$NON-NLS-1$ +public int typeID() { + return T_short; +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/impl/StringConstant.java b/src/java/org/eclipse/jdt/internal/compiler/impl/StringConstant.java new file mode 100644 index 0000000..0248540 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/impl/StringConstant.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.impl; + +public class StringConstant extends Constant { + public String value; + +public StringConstant(String value) { + this.value = value ; +} +public boolean compileTimeEqual(StringConstant right){ + //String are intermed in the compiler==>thus if two string constant + //get to be compared, it is an equal on the vale which is done + if (this.value == null) { + return right.value == null; + } + return this.value.equals(right.value); +} +public String stringValue() { + //spec 15.17.11 + + //the next line do not go into the toString() send....! + return value ; + + /* + String s = value.toString() ; + if (s == null) + return "null"; + else + return s; + */ + +} +public String toString(){ + + return "(String)\"" + value +"\""; } //$NON-NLS-2$ //$NON-NLS-1$ +public int typeID() { + return T_String; +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/ArrayBinding.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/ArrayBinding.java new file mode 100644 index 0000000..da45684 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/ArrayBinding.java @@ -0,0 +1,149 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.impl.Constant; + +public final class ArrayBinding extends TypeBinding { + // creation and initialization of the length field + // the declaringClass of this field is intentionally set to null so it can be distinguished. + public static final FieldBinding ArrayLength = new FieldBinding(LENGTH, IntBinding, AccPublic | AccFinal, null, Constant.NotAConstant); + + public TypeBinding leafComponentType; + public int dimensions; + + char[] constantPoolName; +public ArrayBinding(TypeBinding type, int dimensions) { + this.tagBits |= IsArrayType; + this.leafComponentType = type; + this.dimensions = dimensions; +} +/** + * Answer the receiver's constant pool name. + * NOTE: This method should only be used during/after code gen. + * e.g. '[Ljava/lang/Object;' + */ + +public char[] constantPoolName() { + if (constantPoolName != null) + return constantPoolName; + + char[] brackets = new char[dimensions]; + for (int i = dimensions - 1; i >= 0; i--) brackets[i] = '['; + return constantPoolName = CharOperation.concat(brackets, leafComponentType.signature()); +} +String debugName() { + StringBuffer brackets = new StringBuffer(dimensions * 2); + for (int i = dimensions; --i >= 0;) + brackets.append("[]"); //$NON-NLS-1$ + return leafComponentType.debugName() + brackets.toString(); +} +public int dimensions() { + return this.dimensions; +} + +/* Answer an array whose dimension size is one less than the receiver. +* +* When the receiver's dimension size is one then answer the leaf component type. +*/ + +public TypeBinding elementsType(Scope scope) { + if (dimensions == 1) return leafComponentType; + return scope.createArray(leafComponentType, dimensions - 1); +} +public PackageBinding getPackage() { + return leafComponentType.getPackage(); +} +/* Answer true if the receiver type can be assigned to the argument type (right) +*/ + +public boolean isCompatibleWith(TypeBinding right) { + if (this == right) + return true; + + if (right.isArrayType()) { + ArrayBinding rightArray = (ArrayBinding) right; + if (rightArray.leafComponentType.isBaseType()) + return false; // relying on the fact that all equal arrays are identical + if (dimensions == rightArray.dimensions) + return leafComponentType.isCompatibleWith(rightArray.leafComponentType); + if (dimensions < rightArray.dimensions) + return false; // cannot assign 'String[]' into 'Object[][]' but can assign 'byte[][]' into 'Object[]' + } else { + if (right.isBaseType()) + return false; + } + //Check dimensions - Java does not support explicitly sized dimensions for types. + //However, if it did, the type checking support would go here. + switch (right.leafComponentType().id) { + case T_JavaLangObject : + case T_JavaLangCloneable : + case T_JavaIoSerializable : + return true; + } + return false; +} + +public TypeBinding leafComponentType(){ + return leafComponentType; +} + +/* API +* Answer the problem id associated with the receiver. +* NoError if the receiver is a valid binding. +*/ + +public int problemId() { + return leafComponentType.problemId(); +} +/** +* Answer the source name for the type. +* In the case of member types, as the qualified name from its top level type. +* For example, for a member type N defined inside M & A: "A.M.N". +*/ + +public char[] qualifiedSourceName() { + char[] brackets = new char[dimensions * 2]; + for (int i = dimensions * 2 - 1; i >= 0; i -= 2) { + brackets[i] = ']'; + brackets[i - 1] = '['; + } + return CharOperation.concat(leafComponentType.qualifiedSourceName(), brackets); +} +public char[] readableName() /* java.lang.Object[] */ { + char[] brackets = new char[dimensions * 2]; + for (int i = dimensions * 2 - 1; i >= 0; i -= 2) { + brackets[i] = ']'; + brackets[i - 1] = '['; + } + return CharOperation.concat(leafComponentType.readableName(), brackets); +} +public char[] shortReadableName(){ + char[] brackets = new char[dimensions * 2]; + for (int i = dimensions * 2 - 1; i >= 0; i -= 2) { + brackets[i] = ']'; + brackets[i - 1] = '['; + } + return CharOperation.concat(leafComponentType.shortReadableName(), brackets); +} +public char[] sourceName() { + char[] brackets = new char[dimensions * 2]; + for (int i = dimensions * 2 - 1; i >= 0; i -= 2) { + brackets[i] = ']'; + brackets[i - 1] = '['; + } + return CharOperation.concat(leafComponentType.sourceName(), brackets); +} +public String toString() { + return leafComponentType != null ? debugName() : "NULL TYPE ARRAY"; //$NON-NLS-1$ +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/BaseTypeBinding.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/BaseTypeBinding.java new file mode 100644 index 0000000..501e237 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/BaseTypeBinding.java @@ -0,0 +1,186 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +public final class BaseTypeBinding extends TypeBinding { + + public char[] simpleName; + private char[] constantPoolName; + + BaseTypeBinding(int id, char[] name, char[] constantPoolName) { + + this.tagBits |= IsBaseType; + this.id = id; + this.simpleName = name; + this.constantPoolName = constantPoolName; + } + + /* Answer the receiver's constant pool name. + */ + public char[] constantPoolName() { + + return constantPoolName; + } + + public PackageBinding getPackage() { + + return null; + } + + /* Answer true if the receiver type can be assigned to the argument type (right) + */ + public final boolean isCompatibleWith(TypeBinding right) { + + if (this == right) + return true; + if (!right.isBaseType()) + return this == NullBinding; + + switch (right.id) { + case T_boolean : + case T_byte : + case T_char : + return false; + case T_double : + switch (id) { + case T_byte : + case T_char : + case T_short : + case T_int : + case T_long : + case T_float : + return true; + default : + return false; + } + case T_float : + switch (id) { + case T_byte : + case T_char : + case T_short : + case T_int : + case T_long : + return true; + default : + return false; + } + case T_long : + switch (id) { + case T_byte : + case T_char : + case T_short : + case T_int : + return true; + default : + return false; + } + case T_int : + switch (id) { + case T_byte : + case T_char : + case T_short : + return true; + default : + return false; + } + case T_short : + return (id == T_byte); + } + return false; + } + + public static final boolean isNarrowing(int left, int right) { + + //can "left" store a "right" using some narrowing conversion + //(is left smaller than right) + switch (left) { + case T_boolean : + return right == T_boolean; + case T_char : + case T_byte : + if (right == T_byte) + return true; + case T_short : + if (right == T_short) + return true; + if (right == T_char) + return true; + case T_int : + if (right == T_int) + return true; + case T_long : + if (right == T_long) + return true; + case T_float : + if (right == T_float) + return true; + case T_double : + if (right == T_double) + return true; + default : + return false; + } + } + + public static final boolean isWidening(int left, int right) { + + //can "left" store a "right" using some widening conversion + //(is left "bigger" than right) + switch (left) { + case T_boolean : + return right == T_boolean; + case T_char : + return right == T_char; + case T_double : + if (right == T_double) + return true; + case T_float : + if (right == T_float) + return true; + case T_long : + if (right == T_long) + return true; + case T_int : + if (right == T_int) + return true; + if (right == T_char) + return true; + case T_short : + if (right == T_short) + return true; + case T_byte : + if (right == T_byte) + return true; + default : + return false; + } + } + + public char[] qualifiedSourceName() { + return simpleName; + } + + public char[] readableName() { + return simpleName; + } + + public char[] shortReadableName() { + return simpleName; + } + + public char[] sourceName() { + return simpleName; + } + + public String toString() { + return new String(constantPoolName) + " (id=" + id + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/BaseTypes.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/BaseTypes.java new file mode 100644 index 0000000..b1ec5eb --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/BaseTypes.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +public interface BaseTypes { + final BaseTypeBinding IntBinding = new BaseTypeBinding(TypeIds.T_int, "int".toCharArray(), new char[] {'I'}); //$NON-NLS-1$ + final BaseTypeBinding ByteBinding = new BaseTypeBinding(TypeIds.T_byte, "byte".toCharArray(), new char[] {'B'}); //$NON-NLS-1$ + final BaseTypeBinding ShortBinding = new BaseTypeBinding(TypeIds.T_short, "short".toCharArray(), new char[] {'S'}); //$NON-NLS-1$ + final BaseTypeBinding CharBinding = new BaseTypeBinding(TypeIds.T_char, "char".toCharArray(), new char[] {'C'}); //$NON-NLS-1$ + final BaseTypeBinding LongBinding = new BaseTypeBinding(TypeIds.T_long, "long".toCharArray(), new char[] {'J'}); //$NON-NLS-1$ + final BaseTypeBinding FloatBinding = new BaseTypeBinding(TypeIds.T_float, "float".toCharArray(), new char[] {'F'}); //$NON-NLS-1$ + final BaseTypeBinding DoubleBinding = new BaseTypeBinding(TypeIds.T_double, "double".toCharArray(), new char[] {'D'}); //$NON-NLS-1$ + final BaseTypeBinding BooleanBinding = new BaseTypeBinding(TypeIds.T_boolean, "boolean".toCharArray(), new char[] {'Z'}); //$NON-NLS-1$ + final BaseTypeBinding NullBinding = new BaseTypeBinding(TypeIds.T_null, "null".toCharArray(), new char[] {'N'}); //N stands for null even if it is never internally used //$NON-NLS-1$ + final BaseTypeBinding VoidBinding = new BaseTypeBinding(TypeIds.T_void, "void".toCharArray(), new char[] {'V'}); //$NON-NLS-1$ +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java new file mode 100644 index 0000000..6ada2f8 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java @@ -0,0 +1,550 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration; +import org.eclipse.jdt.internal.compiler.env.IBinaryField; +import org.eclipse.jdt.internal.compiler.env.IBinaryMethod; +import org.eclipse.jdt.internal.compiler.env.IBinaryNestedType; +import org.eclipse.jdt.internal.compiler.env.IBinaryType; +import org.eclipse.jdt.internal.compiler.problem.AbortCompilation; + +/* +Not all fields defined by this type are initialized when it is created. +Some are initialized only when needed. + +Accessors have been provided for some public fields so all TypeBindings have the same API... +but access public fields directly whenever possible. +Non-public fields have accessors which should be used everywhere you expect the field to be initialized. + +null is NOT a valid value for a non-public field... it just means the field is not initialized. +*/ + +public final class BinaryTypeBinding extends ReferenceBinding { + // all of these fields are ONLY guaranteed to be initialized if accessed using their public accessor method + private ReferenceBinding superclass; + private ReferenceBinding enclosingType; + private ReferenceBinding[] superInterfaces; + private FieldBinding[] fields; + private MethodBinding[] methods; + private ReferenceBinding[] memberTypes; + + // For the link with the principle structure + private LookupEnvironment environment; +public BinaryTypeBinding(PackageBinding packageBinding, IBinaryType binaryType, LookupEnvironment environment) { + this.compoundName = CharOperation.splitOn('/', binaryType.getName()); + computeId(); + + this.tagBits |= IsBinaryBinding; + this.environment = environment; + this.fPackage = packageBinding; + this.fileName = binaryType.getFileName(); + + // source name must be one name without "$". + char[] possibleSourceName = this.compoundName[this.compoundName.length - 1]; + int start = CharOperation.lastIndexOf('$', possibleSourceName) + 1; + if (start == 0) { + this.sourceName = possibleSourceName; + } else { + this.sourceName = new char[possibleSourceName.length - start]; + System.arraycopy(possibleSourceName, start, this.sourceName, 0, this.sourceName.length); + } + + this.modifiers = binaryType.getModifiers(); + if (binaryType.isInterface()) + this.modifiers |= AccInterface; + + if (binaryType.isAnonymous()) { + this.tagBits |= AnonymousTypeMask; + } else if (binaryType.isLocal()) { + this.tagBits |= LocalTypeMask; + } else if (binaryType.isMember()) { + this.tagBits |= MemberTypeMask; + } +} + +public FieldBinding[] availableFields() { + FieldBinding[] availableFields = new FieldBinding[fields.length]; + int count = 0; + + for (int i = 0; i < fields.length;i++) { + try { + availableFields[count] = resolveTypeFor(fields[i]); + count++; + } catch (AbortCompilation a){ + // silent abort + } + } + + System.arraycopy(availableFields, 0, availableFields = new FieldBinding[count], 0, count); + return availableFields; +} + +public MethodBinding[] availableMethods() { + if ((modifiers & AccUnresolved) == 0) + return methods; + + MethodBinding[] availableMethods = new MethodBinding[methods.length]; + int count = 0; + + for (int i = 0; i < methods.length;i++) { + try { + availableMethods[count] = resolveTypesFor(methods[i]); + count++; + } catch (AbortCompilation a){ + // silent abort + } + } + System.arraycopy(availableMethods, 0, availableMethods = new MethodBinding[count], 0, count); + return availableMethods; +} + +void cachePartsFrom(IBinaryType binaryType, boolean needFieldsAndMethods) { + + // default initialization for super-interfaces early, in case some aborting compilation error occurs, + // and still want to use binaries passed that point (e.g. type hierarchy resolver, see bug 63748). + this.superInterfaces = NoSuperInterfaces; + + char[] superclassName = binaryType.getSuperclassName(); + if (superclassName != null) + // attempt to find the superclass if it exists in the cache (otherwise - resolve it when requested) + this.superclass = environment.getTypeFromConstantPoolName(superclassName, 0, -1); + + char[] enclosingTypeName = binaryType.getEnclosingTypeName(); + if (enclosingTypeName != null) { + // attempt to find the enclosing type if it exists in the cache (otherwise - resolve it when requested) + this.enclosingType = environment.getTypeFromConstantPoolName(enclosingTypeName, 0, -1); + this.tagBits |= MemberTypeMask; // must be a member type not a top-level or local type + if (this.enclosingType().isStrictfp()) + this.modifiers |= AccStrictfp; + if (this.enclosingType().isDeprecated()) + this.modifiers |= AccDeprecatedImplicitly; + } + + this.memberTypes = NoMemberTypes; + IBinaryNestedType[] memberTypeStructures = binaryType.getMemberTypes(); + if (memberTypeStructures != null) { + int size = memberTypeStructures.length; + if (size > 0) { + this.memberTypes = new ReferenceBinding[size]; + for (int i = 0; i < size; i++) + // attempt to find each member type if it exists in the cache (otherwise - resolve it when requested) + this.memberTypes[i] = environment.getTypeFromConstantPoolName(memberTypeStructures[i].getName(), 0, -1); + } + } + + char[][] interfaceNames = binaryType.getInterfaceNames(); + if (interfaceNames != null) { + int size = interfaceNames.length; + if (size > 0) { + this.superInterfaces = new ReferenceBinding[size]; + for (int i = 0; i < size; i++) + // attempt to find each superinterface if it exists in the cache (otherwise - resolve it when requested) + this.superInterfaces[i] = environment.getTypeFromConstantPoolName(interfaceNames[i], 0, -1); + } + } + if (needFieldsAndMethods) { + createFields(binaryType.getFields()); + createMethods(binaryType.getMethods()); + } else { // protect against incorrect use of the needFieldsAndMethods flag, see 48459 + this.fields = NoFields; + this.methods = NoMethods; + } +} +private void createFields(IBinaryField[] iFields) { + this.fields = NoFields; + if (iFields != null) { + int size = iFields.length; + if (size > 0) { + this.fields = new FieldBinding[size]; + for (int i = 0; i < size; i++) { + IBinaryField field = iFields[i]; + this.fields[i] = + new FieldBinding( + field.getName(), + environment.getTypeFromSignature(field.getTypeName(), 0, -1), + field.getModifiers() | AccUnresolved, + this, + field.getConstant()); + } + } + } +} +private MethodBinding createMethod(IBinaryMethod method) { + int methodModifiers = method.getModifiers() | AccUnresolved; + + ReferenceBinding[] exceptions = NoExceptions; + char[][] exceptionTypes = method.getExceptionTypeNames(); + if (exceptionTypes != null) { + int size = exceptionTypes.length; + if (size > 0) { + exceptions = new ReferenceBinding[size]; + for (int i = 0; i < size; i++) + exceptions[i] = environment.getTypeFromConstantPoolName(exceptionTypes[i], 0, -1); + } + } + + TypeBinding[] parameters = NoParameters; + char[] methodSignature = method.getMethodDescriptor(); // of the form (I[Ljava/jang/String;)V + int numOfParams = 0; + char nextChar; + int index = 0; // first character is always '(' so skip it + while ((nextChar = methodSignature[++index]) != ')') { + if (nextChar != '[') { + numOfParams++; + if (nextChar == 'L') + while ((nextChar = methodSignature[++index]) != ';'){/*empty*/} + } + } + + // Ignore synthetic argument for member types. + int startIndex = (method.isConstructor() && isMemberType() && !isStatic()) ? 1 : 0; + int size = numOfParams - startIndex; + if (size > 0) { + parameters = new TypeBinding[size]; + index = 1; + int end = 0; // first character is always '(' so skip it + for (int i = 0; i < numOfParams; i++) { + while ((nextChar = methodSignature[++end]) == '['){/*empty*/} + if (nextChar == 'L') + while ((nextChar = methodSignature[++end]) != ';'){/*empty*/} + + if (i >= startIndex) // skip the synthetic arg if necessary + parameters[i - startIndex] = environment.getTypeFromSignature(methodSignature, index, end); + index = end + 1; + } + } + + MethodBinding binding = null; + if (method.isConstructor()) + binding = new MethodBinding(methodModifiers, parameters, exceptions, this); + else + binding = new MethodBinding( + methodModifiers, + method.getSelector(), + environment.getTypeFromSignature(methodSignature, index + 1, -1), // index is currently pointing at the ')' + parameters, + exceptions, + this); + return binding; +} +/** + * Create method bindings for binary type, filtering out and synthetics + */ +private void createMethods(IBinaryMethod[] iMethods) { + int total = 0, initialTotal = 0, iClinit = -1; + int[] toSkip = null; + if (iMethods != null) { + total = initialTotal = iMethods.length; + for (int i = total; --i >= 0;) { + IBinaryMethod method = iMethods[i]; + if ((method.getModifiers() & AccSynthetic) != 0) { + // discard synthetics methods + if (toSkip == null) toSkip = new int[iMethods.length]; + toSkip[i] = -1; + total--; + } else if (iClinit == -1) { + char[] methodName = method.getSelector(); + if (methodName.length == 8 && methodName[0] == '<') { + // discard + iClinit = i; + total--; + } + } + } + } + if (total == 0) { + this.methods = NoMethods; + return; + } + + this.methods = new MethodBinding[total]; + if (total == initialTotal) { + for (int i = 0; i < initialTotal; i++) + this.methods[i] = createMethod(iMethods[i]); + } else { + for (int i = 0, index = 0; i < initialTotal; i++) + if (iClinit != i && (toSkip == null || toSkip[i] != -1)) + this.methods[index++] = createMethod(iMethods[i]); + } + modifiers |= AccUnresolved; // until methods() is sent +} +/* Answer the receiver's enclosing type... null if the receiver is a top level type. +* +* NOTE: enclosingType of a binary type is resolved when needed +*/ + +public ReferenceBinding enclosingType() { + if (enclosingType == null) + return null; + if (enclosingType instanceof UnresolvedReferenceBinding) + enclosingType = ((UnresolvedReferenceBinding) enclosingType).resolve(environment); + return enclosingType; +} +// NOTE: the type of each field of a binary type is resolved when needed + +public FieldBinding[] fields() { + for (int i = fields.length; --i >= 0;) + resolveTypeFor(fields[i]); + return fields; +} +// NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed + +public MethodBinding getExactConstructor(TypeBinding[] argumentTypes) { + int argCount = argumentTypes.length; + nextMethod : for (int m = methods.length; --m >= 0;) { + MethodBinding method = methods[m]; + if (method.selector == ConstructorDeclaration.ConstantPoolName && method.parameters.length == argCount) { + resolveTypesFor(method); + TypeBinding[] toMatch = method.parameters; + for (int p = 0; p < argCount; p++) + if (toMatch[p] != argumentTypes[p]) + continue nextMethod; + return method; + } + } + return null; +} +// NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed +// searches up the hierarchy as long as no potential (but not exact) match was found. + +public MethodBinding getExactMethod(char[] selector, TypeBinding[] argumentTypes) { + int argCount = argumentTypes.length; + int selectorLength = selector.length; + boolean foundNothing = true; + nextMethod : for (int m = methods.length; --m >= 0;) { + MethodBinding method = methods[m]; + if (method.selector.length == selectorLength && CharOperation.equals(method.selector, selector)) { + foundNothing = false; // inner type lookups must know that a method with this name exists + if (method.parameters.length == argCount) { + resolveTypesFor(method); + TypeBinding[] toMatch = method.parameters; + for (int p = 0; p < argCount; p++) + if (toMatch[p] != argumentTypes[p]) + continue nextMethod; + return method; + } + } + } + + if (foundNothing) { + if (isInterface()) { + if (superInterfaces.length == 1) + return superInterfaces[0].getExactMethod(selector, argumentTypes); + } else if (superclass != null) { + return superclass.getExactMethod(selector, argumentTypes); + } + } + return null; +} +// NOTE: the type of a field of a binary type is resolved when needed + +public FieldBinding getField(char[] fieldName, boolean needResolve) { + int fieldLength = fieldName.length; + for (int f = fields.length; --f >= 0;) { + char[] name = fields[f].name; + if (name.length == fieldLength && CharOperation.equals(name, fieldName)) + return needResolve ? resolveTypeFor(fields[f]) : fields[f]; + } + return null; +} +/** + * Rewrite of default getMemberType to avoid resolving eagerly all member types when one is requested + */ +public ReferenceBinding getMemberType(char[] typeName) { + for (int i = this.memberTypes.length; --i >= 0;) { + ReferenceBinding memberType = this.memberTypes[i]; + if (memberType instanceof UnresolvedReferenceBinding) { + char[] name = memberType.sourceName; // source name is qualified with enclosing type name + int prefixLength = this.compoundName[this.compoundName.length - 1].length + 1; // enclosing$ + if (name.length == (prefixLength + typeName.length)) // enclosing $ typeName + if (CharOperation.fragmentEquals(typeName, name, prefixLength, true)) // only check trailing portion + return this.memberTypes[i] = ((UnresolvedReferenceBinding) memberType).resolve(environment); + } else if (CharOperation.equals(typeName, memberType.sourceName)) { + return memberType; + } + } + return null; +} +// NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed + +public MethodBinding[] getMethods(char[] selector) { + int count = 0; + int lastIndex = -1; + int selectorLength = selector.length; + for (int m = 0, length = methods.length; m < length; m++) { + MethodBinding method = methods[m]; + if (method.selector.length == selectorLength && CharOperation.equals(method.selector, selector)) { + resolveTypesFor(method); + count++; + lastIndex = m; + } + } + if (count == 1) + return new MethodBinding[] {methods[lastIndex]}; + if (count > 0) { + MethodBinding[] result = new MethodBinding[count]; + count = 0; + for (int m = 0; m <= lastIndex; m++) { + MethodBinding method = methods[m]; + if (method.selector.length == selectorLength && CharOperation.equals(method.selector, selector)) + result[count++] = method; + } + return result; + } + return NoMethods; +} +public boolean hasMemberTypes() { + return this.memberTypes.length > 0; +} +// NOTE: member types of binary types are resolved when needed + +public ReferenceBinding[] memberTypes() { + for (int i = memberTypes.length; --i >= 0;) + if (memberTypes[i] instanceof UnresolvedReferenceBinding) + memberTypes[i] = ((UnresolvedReferenceBinding) memberTypes[i]).resolve(environment); + return memberTypes; +} +// NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed + +public MethodBinding[] methods() { + if ((modifiers & AccUnresolved) == 0) + return methods; + + for (int i = methods.length; --i >= 0;) + resolveTypesFor(methods[i]); + modifiers ^= AccUnresolved; + return methods; +} +TypeBinding resolveType(TypeBinding type) { + if (type instanceof UnresolvedReferenceBinding) + return ((UnresolvedReferenceBinding) type).resolve(environment); + if (type instanceof ArrayBinding) { + ArrayBinding array = (ArrayBinding) type; + if (array.leafComponentType instanceof UnresolvedReferenceBinding) + array.leafComponentType = ((UnresolvedReferenceBinding) array.leafComponentType).resolve(environment); + } + return type; +} +private FieldBinding resolveTypeFor(FieldBinding field) { + if ((field.modifiers & AccUnresolved) != 0) { + field.type = resolveType(field.type); + field.modifiers ^= AccUnresolved; + } + return field; +} +private MethodBinding resolveTypesFor(MethodBinding method) { + if ((method.modifiers & AccUnresolved) == 0) + return method; + + if (!method.isConstructor()) + method.returnType = resolveType(method.returnType); + for (int i = method.parameters.length; --i >= 0;) + method.parameters[i] = resolveType(method.parameters[i]); + for (int i = method.thrownExceptions.length; --i >= 0;) + if (method.thrownExceptions[i] instanceof UnresolvedReferenceBinding) + method.thrownExceptions[i] = ((UnresolvedReferenceBinding) method.thrownExceptions[i]).resolve(environment); + method.modifiers ^= AccUnresolved; + return method; +} +/* Answer the receiver's superclass... null if the receiver is Object or an interface. +* +* NOTE: superclass of a binary type is resolved when needed +*/ + +public ReferenceBinding superclass() { + if (superclass == null) + return null; + if (superclass instanceof UnresolvedReferenceBinding) + superclass = ((UnresolvedReferenceBinding) superclass).resolve(environment); + return superclass; +} +// NOTE: superInterfaces of binary types are resolved when needed + +public ReferenceBinding[] superInterfaces() { + for (int i = superInterfaces.length; --i >= 0;) + if (superInterfaces[i] instanceof UnresolvedReferenceBinding) + superInterfaces[i] = ((UnresolvedReferenceBinding) superInterfaces[i]).resolve(environment); + return superInterfaces; +} +MethodBinding[] unResolvedMethods() { // for the MethodVerifier so it doesn't resolve types + return methods; +} +public String toString() { + String s = ""; //$NON-NLS-1$ + + if (isDeprecated()) s += "deprecated "; //$NON-NLS-1$ + if (isPublic()) s += "public "; //$NON-NLS-1$ + if (isProtected()) s += "protected "; //$NON-NLS-1$ + if (isPrivate()) s += "private "; //$NON-NLS-1$ + if (isAbstract() && isClass()) s += "abstract "; //$NON-NLS-1$ + if (isStatic() && isNestedType()) s += "static "; //$NON-NLS-1$ + if (isFinal()) s += "final "; //$NON-NLS-1$ + + s += isInterface() ? "interface " : "class "; //$NON-NLS-1$ //$NON-NLS-2$ + s += (compoundName != null) ? CharOperation.toString(compoundName) : "UNNAMED TYPE"; //$NON-NLS-1$ + + s += "\n\textends "; //$NON-NLS-1$ + s += (superclass != null) ? superclass.debugName() : "NULL TYPE"; //$NON-NLS-1$ + + if (superInterfaces != null) { + if (superInterfaces != NoSuperInterfaces) { + s += "\n\timplements : "; //$NON-NLS-1$ + for (int i = 0, length = superInterfaces.length; i < length; i++) { + if (i > 0) + s += ", "; //$NON-NLS-1$ + s += (superInterfaces[i] != null) ? superInterfaces[i].debugName() : "NULL TYPE"; //$NON-NLS-1$ + } + } + } else { + s += "NULL SUPERINTERFACES"; //$NON-NLS-1$ + } + + if (enclosingType != null) { + s += "\n\tenclosing type : "; //$NON-NLS-1$ + s += enclosingType.debugName(); + } + + if (fields != null) { + if (fields != NoFields) { + s += "\n/* fields */"; //$NON-NLS-1$ + for (int i = 0, length = fields.length; i < length; i++) + s += (fields[i] != null) ? "\n" + fields[i].toString() : "\nNULL FIELD"; //$NON-NLS-1$ //$NON-NLS-2$ + } + } else { + s += "NULL FIELDS"; //$NON-NLS-1$ + } + + if (methods != null) { + if (methods != NoMethods) { + s += "\n/* methods */"; //$NON-NLS-1$ + for (int i = 0, length = methods.length; i < length; i++) + s += (methods[i] != null) ? "\n" + methods[i].toString() : "\nNULL METHOD"; //$NON-NLS-1$ //$NON-NLS-2$ + } + } else { + s += "NULL METHODS"; //$NON-NLS-1$ + } + + if (memberTypes != null) { + if (memberTypes != NoMemberTypes) { + s += "\n/* members */"; //$NON-NLS-1$ + for (int i = 0, length = memberTypes.length; i < length; i++) + s += (memberTypes[i] != null) ? "\n" + memberTypes[i].toString() : "\nNULL TYPE"; //$NON-NLS-1$ //$NON-NLS-2$ + } + } else { + s += "NULL MEMBER TYPES"; //$NON-NLS-1$ + } + + s += "\n\n\n"; //$NON-NLS-1$ + return s; +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/Binding.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/Binding.java new file mode 100644 index 0000000..d6225aa --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/Binding.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +public abstract class Binding implements BindingIds, CompilerModifiers, ProblemReasons { + /* API + * Answer the receiver's binding type from Binding.BindingID. + * + * Note: Do NOT expect this to be used very often... only in switch statements with + * more than 2 possible choices. + */ + public abstract int bindingType(); + /* API + * Answer true if the receiver is not a problem binding + */ + + public final boolean isValidBinding() { + return problemId() == NoError; + } + /* API + * Answer the problem id associated with the receiver. + * NoError if the receiver is a valid binding. + */ + + public int problemId() { + return NoError; + } + /* Answer a printable representation of the receiver. + */ + public abstract char[] readableName(); + + /* Shorter printable representation of the receiver (no qualified type) + */ + public char[] shortReadableName(){ + return readableName(); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/BindingIds.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/BindingIds.java new file mode 100644 index 0000000..9f2e688 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/BindingIds.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +public interface BindingIds { + final int FIELD = 1; + final int LOCAL = 2; + final int VARIABLE = FIELD | LOCAL; + final int TYPE = 4; + final int METHOD = 8; + final int PACKAGE = 16; + final int IMPORT = 32; +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java new file mode 100644 index 0000000..f0f9451 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java @@ -0,0 +1,826 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.ast.*; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.codegen.CodeStream; +import org.eclipse.jdt.internal.compiler.impl.Constant; +import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; + +public class BlockScope extends Scope { + + // Local variable management + public LocalVariableBinding[] locals; + public int localIndex; // position for next variable + public int startIndex; // start position in this scope - for ordering scopes vs. variables + public int offset; // for variable allocation throughout scopes + public int maxOffset; // for variable allocation throughout scopes + + // finally scopes must be shifted behind respective try&catch scope(s) so as to avoid + // collisions of secret variables (return address, save value). + public BlockScope[] shiftScopes; + + public final static VariableBinding[] EmulationPathToImplicitThis = {}; + public final static VariableBinding[] NoEnclosingInstanceInConstructorCall = {}; + public final static VariableBinding[] NoEnclosingInstanceInStaticContext = {}; + + public Scope[] subscopes = new Scope[1]; // need access from code assist + public int subscopeCount = 0; // need access from code assist + + // record the current case statement being processed (for entire switch case block). + public CaseStatement switchCase; // from 1.4 on, local types should not be accessed across switch case blocks (52221) + + protected BlockScope(int kind, Scope parent) { + + super(kind, parent); + } + + public BlockScope(BlockScope parent) { + + this(parent, true); + } + + public BlockScope(BlockScope parent, boolean addToParentScope) { + + this(BLOCK_SCOPE, parent); + locals = new LocalVariableBinding[5]; + if (addToParentScope) parent.addSubscope(this); + this.startIndex = parent.localIndex; + } + + public BlockScope(BlockScope parent, int variableCount) { + + this(BLOCK_SCOPE, parent); + locals = new LocalVariableBinding[variableCount]; + parent.addSubscope(this); + this.startIndex = parent.localIndex; + } + + /* Create the class scope & binding for the anonymous type. + */ + public final void addAnonymousType( + TypeDeclaration anonymousType, + ReferenceBinding superBinding) { + + ClassScope anonymousClassScope = new ClassScope(this, anonymousType); + anonymousClassScope.buildAnonymousTypeBinding( + enclosingSourceType(), + superBinding); + } + + /* Create the class scope & binding for the local type. + */ + public final void addLocalType(TypeDeclaration localType) { + + // check that the localType does not conflict with an enclosing type + ReferenceBinding type = enclosingSourceType(); + do { + if (CharOperation.equals(type.sourceName, localType.name)) { + problemReporter().hidingEnclosingType(localType); + return; + } + type = type.enclosingType(); + } while (type != null); + + // check that the localType does not conflict with another sibling local type + Scope scope = this; + do { + if (((BlockScope) scope).findLocalType(localType.name) != null) { + problemReporter().duplicateNestedType(localType); + return; + } + } while ((scope = scope.parent) instanceof BlockScope); + + ClassScope localTypeScope = new ClassScope(this, localType); + addSubscope(localTypeScope); + localTypeScope.buildLocalTypeBinding(enclosingSourceType()); + } + + /* Insert a local variable into a given scope, updating its position + * and checking there are not too many locals or arguments allocated. + */ + public final void addLocalVariable(LocalVariableBinding binding) { + + checkAndSetModifiersForVariable(binding); + + // insert local in scope + if (localIndex == locals.length) + System.arraycopy( + locals, + 0, + (locals = new LocalVariableBinding[localIndex * 2]), + 0, + localIndex); + locals[localIndex++] = binding; + + // update local variable binding + binding.declaringScope = this; + binding.id = this.outerMostMethodScope().analysisIndex++; + // share the outermost method scope analysisIndex + } + + public void addSubscope(Scope childScope) { + if (subscopeCount == subscopes.length) + System.arraycopy( + subscopes, + 0, + (subscopes = new Scope[subscopeCount * 2]), + 0, + subscopeCount); + subscopes[subscopeCount++] = childScope; + } + + /* Answer true if the receiver is suitable for assigning final blank fields. + * + * in other words, it is inside an initializer, a constructor or a clinit + */ + public final boolean allowBlankFinalFieldAssignment(FieldBinding binding) { + + if (enclosingSourceType() != binding.declaringClass) + return false; + + MethodScope methodScope = methodScope(); + if (methodScope.isStatic != binding.isStatic()) + return false; + return methodScope.isInsideInitializer() // inside initializer + || ((AbstractMethodDeclaration) methodScope.referenceContext) + .isInitializationMethod(); // inside constructor or clinit + } + String basicToString(int tab) { + String newLine = "\n"; //$NON-NLS-1$ + for (int i = tab; --i >= 0;) + newLine += "\t"; //$NON-NLS-1$ + + String s = newLine + "--- Block Scope ---"; //$NON-NLS-1$ + newLine += "\t"; //$NON-NLS-1$ + s += newLine + "locals:"; //$NON-NLS-1$ + for (int i = 0; i < localIndex; i++) + s += newLine + "\t" + locals[i].toString(); //$NON-NLS-1$ + s += newLine + "startIndex = " + startIndex; //$NON-NLS-1$ + return s; + } + + private void checkAndSetModifiersForVariable(LocalVariableBinding varBinding) { + + int modifiers = varBinding.modifiers; + if ((modifiers & AccAlternateModifierProblem) != 0 && varBinding.declaration != null){ + problemReporter().duplicateModifierForVariable(varBinding.declaration, this instanceof MethodScope); + } + int realModifiers = modifiers & AccJustFlag; + + int unexpectedModifiers = ~AccFinal; + if ((realModifiers & unexpectedModifiers) != 0 && varBinding.declaration != null){ + problemReporter().illegalModifierForVariable(varBinding.declaration, this instanceof MethodScope); + } + varBinding.modifiers = modifiers; + } + + /* Compute variable positions in scopes given an initial position offset + * ignoring unused local variables. + * + * No argument is expected here (ilocal is the first non-argument local of the outermost scope) + * Arguments are managed by the MethodScope method + */ + void computeLocalVariablePositions(int ilocal, int initOffset, CodeStream codeStream) { + + this.offset = initOffset; + this.maxOffset = initOffset; + + // local variable init + int maxLocals = this.localIndex; + boolean hasMoreVariables = ilocal < maxLocals; + + // scope init + int iscope = 0, maxScopes = this.subscopeCount; + boolean hasMoreScopes = maxScopes > 0; + + // iterate scopes and variables in parallel + while (hasMoreVariables || hasMoreScopes) { + if (hasMoreScopes + && (!hasMoreVariables || (subscopes[iscope].startIndex() <= ilocal))) { + // consider subscope first + if (subscopes[iscope] instanceof BlockScope) { + BlockScope subscope = (BlockScope) subscopes[iscope]; + int subOffset = subscope.shiftScopes == null ? this.offset : subscope.maxShiftedOffset(); + subscope.computeLocalVariablePositions(0, subOffset, codeStream); + if (subscope.maxOffset > this.maxOffset) + this.maxOffset = subscope.maxOffset; + } + hasMoreScopes = ++iscope < maxScopes; + } else { + + // consider variable first + LocalVariableBinding local = locals[ilocal]; // if no local at all, will be locals[ilocal]==null + + // check if variable is actually used, and may force it to be preserved + boolean generateCurrentLocalVar = (local.useFlag == LocalVariableBinding.USED && (local.constant == Constant.NotAConstant)); + + // do not report fake used variable + if (local.useFlag == LocalVariableBinding.UNUSED + && (local.declaration != null) // unused (and non secret) local + && ((local.declaration.bits & ASTNode.IsLocalDeclarationReachableMASK) != 0)) { // declaration is reachable + + if (!(local.declaration instanceof Argument)) // do not report unused catch arguments + this.problemReporter().unusedLocalVariable(local.declaration); + } + + // could be optimized out, but does need to preserve unread variables ? + if (!generateCurrentLocalVar) { + if (local.declaration != null && environment().options.preserveAllLocalVariables) { + generateCurrentLocalVar = true; // force it to be preserved in the generated code + local.useFlag = LocalVariableBinding.USED; + } + } + + // allocate variable + if (generateCurrentLocalVar) { + + if (local.declaration != null) { + codeStream.record(local); // record user-defined local variables for attribute generation + } + // assign variable position + local.resolvedPosition = this.offset; + + if ((local.type == LongBinding) || (local.type == DoubleBinding)) { + this.offset += 2; + } else { + this.offset++; + } + if (this.offset > 0xFFFF) { // no more than 65535 words of locals + this.problemReporter().noMoreAvailableSpaceForLocal( + local, + local.declaration == null ? (ASTNode)this.methodScope().referenceContext : local.declaration); + } + } else { + local.resolvedPosition = -1; // not generated + } + hasMoreVariables = ++ilocal < maxLocals; + } + } + if (this.offset > this.maxOffset) + this.maxOffset = this.offset; + } + + /* + * Record the suitable binding denoting a synthetic field or constructor argument, + * mapping to the actual outer local variable in the scope context. + * Note that this may not need any effect, in case the outer local variable does not + * need to be emulated and can directly be used as is (using its back pointer to its + * declaring scope). + */ + public void emulateOuterAccess(LocalVariableBinding outerLocalVariable) { + + MethodScope currentMethodScope; + if ((currentMethodScope = this.methodScope()) + != outerLocalVariable.declaringScope.methodScope()) { + NestedTypeBinding currentType = (NestedTypeBinding) this.enclosingSourceType(); + + //do nothing for member types, pre emulation was performed already + if (!currentType.isLocalType()) { + return; + } + // must also add a synthetic field if we're not inside a constructor + if (!currentMethodScope.isInsideInitializerOrConstructor()) { + currentType.addSyntheticArgumentAndField(outerLocalVariable); + } else { + currentType.addSyntheticArgument(outerLocalVariable); + } + } + } + + /* Note that it must never produce a direct access to the targetEnclosingType, + * but instead a field sequence (this$2.this$1.this$0) so as to handle such a test case: + * + * class XX { + * void foo() { + * class A { + * class B { + * class C { + * boolean foo() { + * return (Object) A.this == (Object) B.this; + * } + * } + * } + * } + * new A().new B().new C(); + * } + * } + * where we only want to deal with ONE enclosing instance for C (could not figure out an A for C) + */ + public final ReferenceBinding findLocalType(char[] name) { + + long compliance = environment().options.complianceLevel; + for (int i = 0, length = subscopeCount; i < length; i++) { + if (subscopes[i] instanceof ClassScope) { + LocalTypeBinding sourceType = (LocalTypeBinding)((ClassScope) subscopes[i]).referenceContext.binding; + // from 1.4 on, local types should not be accessed across switch case blocks (52221) + if (compliance >= ClassFileConstants.JDK1_4 && sourceType.switchCase != this.switchCase) continue; + if (CharOperation.equals(sourceType.sourceName(), name)) + return sourceType; + } + } + return null; + } + + public LocalVariableBinding findVariable(char[] variable) { + + int varLength = variable.length; + for (int i = 0, length = locals.length; i < length; i++) { + LocalVariableBinding local = locals[i]; + if (local == null) + return null; + if (local.name.length == varLength && CharOperation.equals(local.name, variable)) + return local; + } + return null; + } + /* API + * flag is a mask of the following values VARIABLE (= FIELD or LOCAL), TYPE. + * Only bindings corresponding to the mask will be answered. + * + * if the VARIABLE mask is set then + * If the first name provided is a field (or local) then the field (or local) is answered + * Otherwise, package names and type names are consumed until a field is found. + * In this case, the field is answered. + * + * if the TYPE mask is set, + * package names and type names are consumed until the end of the input. + * Only if all of the input is consumed is the type answered + * + * All other conditions are errors, and a problem binding is returned. + * + * NOTE: If a problem binding is returned, senders should extract the compound name + * from the binding & not assume the problem applies to the entire compoundName. + * + * The VARIABLE mask has precedence over the TYPE mask. + * + * InvocationSite implements + * isSuperAccess(); this is used to determine if the discovered field is visible. + * setFieldIndex(int); this is used to record the number of names that were consumed. + * + * For example, getBinding({"foo","y","q", VARIABLE, site) will answer + * the binding for the field or local named "foo" (or an error binding if none exists). + * In addition, setFieldIndex(1) will be sent to the invocation site. + * If a type named "foo" exists, it will not be detected (and an error binding will be answered) + * + * IMPORTANT NOTE: This method is written under the assumption that compoundName is longer than length 1. + */ + public Binding getBinding(char[][] compoundName, int mask, InvocationSite invocationSite, boolean needResolve) { + + Binding binding = getBinding(compoundName[0], mask | TYPE | PACKAGE, invocationSite, needResolve); + invocationSite.setFieldIndex(1); + if (binding instanceof VariableBinding) return binding; + compilationUnitScope().recordSimpleReference(compoundName[0]); + if (!binding.isValidBinding()) return binding; + + int length = compoundName.length; + int currentIndex = 1; + foundType : if (binding instanceof PackageBinding) { + PackageBinding packageBinding = (PackageBinding) binding; + while (currentIndex < length) { + compilationUnitScope().recordReference(packageBinding.compoundName, compoundName[currentIndex]); + binding = packageBinding.getTypeOrPackage(compoundName[currentIndex++]); + invocationSite.setFieldIndex(currentIndex); + if (binding == null) { + if (currentIndex == length) { + // must be a type if its the last name, otherwise we have no idea if its a package or type + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + NotFound); + } + return new ProblemBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + NotFound); + } + if (binding instanceof ReferenceBinding) { + if (!binding.isValidBinding()) + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + binding.problemId()); + if (!((ReferenceBinding) binding).canBeSeenBy(this)) + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + (ReferenceBinding) binding, + NotVisible); + break foundType; + } + packageBinding = (PackageBinding) binding; + } + + // It is illegal to request a PACKAGE from this method. + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + NotFound); + } + + // know binding is now a ReferenceBinding + while (currentIndex < length) { + ReferenceBinding typeBinding = (ReferenceBinding) binding; + char[] nextName = compoundName[currentIndex++]; + invocationSite.setFieldIndex(currentIndex); + invocationSite.setActualReceiverType(typeBinding); + if ((mask & FIELD) != 0 && (binding = findField(typeBinding, nextName, invocationSite, true /*resolve*/)) != null) { + if (!binding.isValidBinding()) + return new ProblemFieldBinding( + ((FieldBinding) binding).declaringClass, + CharOperation.subarray(compoundName, 0, currentIndex), + binding.problemId()); + break; // binding is now a field + } + if ((binding = findMemberType(nextName, typeBinding)) == null) { + if ((mask & FIELD) != 0) { + return new ProblemBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + typeBinding, + NotFound); + } + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + typeBinding, + NotFound); + } + if (!binding.isValidBinding()) + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + binding.problemId()); + } + if ((mask & FIELD) != 0 && (binding instanceof FieldBinding)) { + // was looking for a field and found a field + FieldBinding field = (FieldBinding) binding; + if (!field.isStatic()) + return new ProblemFieldBinding( + field.declaringClass, + CharOperation.subarray(compoundName, 0, currentIndex), + NonStaticReferenceInStaticContext); + return binding; + } + if ((mask & TYPE) != 0 && (binding instanceof ReferenceBinding)) { + // was looking for a type and found a type + return binding; + } + + // handle the case when a field or type was asked for but we resolved the compoundName to a type or field + return new ProblemBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + NotFound); + } + + // Added for code assist... NOT Public API + public final Binding getBinding( + char[][] compoundName, + InvocationSite invocationSite) { + int currentIndex = 0; + int length = compoundName.length; + Binding binding = + getBinding( + compoundName[currentIndex++], + VARIABLE | TYPE | PACKAGE, + invocationSite, + true /*resolve*/); + if (!binding.isValidBinding()) + return binding; + + foundType : if (binding instanceof PackageBinding) { + while (currentIndex < length) { + PackageBinding packageBinding = (PackageBinding) binding; + binding = packageBinding.getTypeOrPackage(compoundName[currentIndex++]); + if (binding == null) { + if (currentIndex == length) { + // must be a type if its the last name, otherwise we have no idea if its a package or type + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + NotFound); + } + return new ProblemBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + NotFound); + } + if (binding instanceof ReferenceBinding) { + if (!binding.isValidBinding()) + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + binding.problemId()); + if (!((ReferenceBinding) binding).canBeSeenBy(this)) + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + (ReferenceBinding) binding, + NotVisible); + break foundType; + } + } + return binding; + } + + foundField : if (binding instanceof ReferenceBinding) { + while (currentIndex < length) { + ReferenceBinding typeBinding = (ReferenceBinding) binding; + char[] nextName = compoundName[currentIndex++]; + if ((binding = findField(typeBinding, nextName, invocationSite, true /*resolve*/)) != null) { + if (!binding.isValidBinding()) + return new ProblemFieldBinding( + ((FieldBinding) binding).declaringClass, + CharOperation.subarray(compoundName, 0, currentIndex), + binding.problemId()); + if (!((FieldBinding) binding).isStatic()) + return new ProblemFieldBinding( + ((FieldBinding) binding).declaringClass, + CharOperation.subarray(compoundName, 0, currentIndex), + NonStaticReferenceInStaticContext); + break foundField; // binding is now a field + } + if ((binding = findMemberType(nextName, typeBinding)) == null) + return new ProblemBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + typeBinding, + NotFound); + if (!binding.isValidBinding()) + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + binding.problemId()); + } + return binding; + } + + VariableBinding variableBinding = (VariableBinding) binding; + while (currentIndex < length) { + TypeBinding typeBinding = variableBinding.type; + if (typeBinding == null) + return new ProblemFieldBinding( + null, + CharOperation.subarray(compoundName, 0, currentIndex + 1), + NotFound); + variableBinding = + findField(typeBinding, compoundName[currentIndex++], invocationSite, true /*resolve*/); + if (variableBinding == null) + return new ProblemFieldBinding( + null, + CharOperation.subarray(compoundName, 0, currentIndex), + NotFound); + if (!variableBinding.isValidBinding()) + return variableBinding; + } + return variableBinding; + } + + /* + * This retrieves the argument that maps to an enclosing instance of the suitable type, + * if not found then answers nil -- do not create one + * + * #implicitThis : the implicit this will be ok + * #((arg) this$n) : available as a constructor arg + * #((arg) this$n ... this$p) : available as as a constructor arg + a sequence of fields + * #((fieldDescr) this$n ... this$p) : available as a sequence of fields + * nil : not found + * + * Note that this algorithm should answer the shortest possible sequence when + * shortcuts are available: + * this$0 . this$0 . this$0 + * instead of + * this$2 . this$1 . this$0 . this$1 . this$0 + * thus the code generation will be more compact and runtime faster + */ + public VariableBinding[] getEmulationPath(LocalVariableBinding outerLocalVariable) { + + MethodScope currentMethodScope = this.methodScope(); + SourceTypeBinding sourceType = currentMethodScope.enclosingSourceType(); + + // identity check + if (currentMethodScope == outerLocalVariable.declaringScope.methodScope()) { + return new VariableBinding[] { outerLocalVariable }; + // implicit this is good enough + } + // use synthetic constructor arguments if possible + if (currentMethodScope.isInsideInitializerOrConstructor() + && (sourceType.isNestedType())) { + SyntheticArgumentBinding syntheticArg; + if ((syntheticArg = ((NestedTypeBinding) sourceType).getSyntheticArgument(outerLocalVariable)) != null) { + return new VariableBinding[] { syntheticArg }; + } + } + // use a synthetic field then + if (!currentMethodScope.isStatic) { + FieldBinding syntheticField; + if ((syntheticField = sourceType.getSyntheticField(outerLocalVariable)) != null) { + return new VariableBinding[] { syntheticField }; + } + } + return null; + } + + /* + * This retrieves the argument that maps to an enclosing instance of the suitable type, + * if not found then answers nil -- do not create one + * + * #implicitThis : the implicit this will be ok + * #((arg) this$n) : available as a constructor arg + * #((arg) this$n access$m... access$p) : available as as a constructor arg + a sequence of synthetic accessors to synthetic fields + * #((fieldDescr) this$n access#m... access$p) : available as a first synthetic field + a sequence of synthetic accessors to synthetic fields + * null : not found + * jls 15.9.2 + http://www.ergnosis.com/java-spec-report/java-language/jls-8.8.5.1-d.html + */ + public Object[] getEmulationPath( + ReferenceBinding targetEnclosingType, + boolean onlyExactMatch, + boolean ignoreEnclosingArgInConstructorCall) { + + MethodScope currentMethodScope = this.methodScope(); + SourceTypeBinding sourceType = currentMethodScope.enclosingSourceType(); + + // use 'this' if possible + if (!currentMethodScope.isConstructorCall && !currentMethodScope.isStatic) { + if (sourceType == targetEnclosingType || (!onlyExactMatch && targetEnclosingType.isSuperclassOf(sourceType))) { + return EmulationPathToImplicitThis; // implicit this is good enough + } + } + if (!sourceType.isNestedType() || sourceType.isStatic()) { // no emulation from within non-inner types + if (currentMethodScope.isConstructorCall) { + return NoEnclosingInstanceInConstructorCall; + } else if (currentMethodScope.isStatic){ + return NoEnclosingInstanceInStaticContext; + } + return null; + } + boolean insideConstructor = currentMethodScope.isInsideInitializerOrConstructor(); + // use synthetic constructor arguments if possible + if (insideConstructor) { + SyntheticArgumentBinding syntheticArg; + if ((syntheticArg = ((NestedTypeBinding) sourceType).getSyntheticArgument(targetEnclosingType, onlyExactMatch)) != null) { + // reject allocation and super constructor call + if (ignoreEnclosingArgInConstructorCall + && currentMethodScope.isConstructorCall + && (sourceType == targetEnclosingType || (!onlyExactMatch && targetEnclosingType.isSuperclassOf(sourceType)))) { + return NoEnclosingInstanceInConstructorCall; + } + return new Object[] { syntheticArg }; + } + } + + // use a direct synthetic field then + if (currentMethodScope.isStatic) { + return NoEnclosingInstanceInStaticContext; + } + FieldBinding syntheticField = sourceType.getSyntheticField(targetEnclosingType, onlyExactMatch); + if (syntheticField != null) { + if (currentMethodScope.isConstructorCall){ + return NoEnclosingInstanceInConstructorCall; + } + return new Object[] { syntheticField }; + } + // could be reached through a sequence of enclosing instance link (nested members) + Object[] path = new Object[2]; // probably at least 2 of them + ReferenceBinding currentType = sourceType.enclosingType(); + if (insideConstructor) { + path[0] = ((NestedTypeBinding) sourceType).getSyntheticArgument(currentType, onlyExactMatch); + } else { + if (currentMethodScope.isConstructorCall){ + return NoEnclosingInstanceInConstructorCall; + } + path[0] = sourceType.getSyntheticField(currentType, onlyExactMatch); + } + if (path[0] != null) { // keep accumulating + + int count = 1; + ReferenceBinding currentEnclosingType; + while ((currentEnclosingType = currentType.enclosingType()) != null) { + + //done? + if (currentType == targetEnclosingType + || (!onlyExactMatch && targetEnclosingType.isSuperclassOf(currentType))) break; + + if (currentMethodScope != null) { + currentMethodScope = currentMethodScope.enclosingMethodScope(); + if (currentMethodScope != null && currentMethodScope.isConstructorCall){ + return NoEnclosingInstanceInConstructorCall; + } + if (currentMethodScope != null && currentMethodScope.isStatic){ + return NoEnclosingInstanceInStaticContext; + } + } + + syntheticField = ((NestedTypeBinding) currentType).getSyntheticField(currentEnclosingType, onlyExactMatch); + if (syntheticField == null) break; + + // append inside the path + if (count == path.length) { + System.arraycopy(path, 0, (path = new Object[count + 1]), 0, count); + } + // private access emulation is necessary since synthetic field is private + path[count++] = ((SourceTypeBinding) syntheticField.declaringClass).addSyntheticMethod(syntheticField, true); + currentType = currentEnclosingType; + } + if (currentType == targetEnclosingType + || (!onlyExactMatch && targetEnclosingType.isSuperclassOf(currentType))) { + return path; + } + } + return null; + } + + /* Answer true if the variable name already exists within the receiver's scope. + */ + public final boolean isDuplicateLocalVariable(char[] name) { + BlockScope current = this; + while (true) { + for (int i = 0; i < localIndex; i++) { + if (CharOperation.equals(name, current.locals[i].name)) + return true; + } + if (current.kind != BLOCK_SCOPE) return false; + current = (BlockScope)current.parent; + } + } + + public int maxShiftedOffset() { + int max = -1; + if (this.shiftScopes != null){ + for (int i = 0, length = this.shiftScopes.length; i < length; i++){ + int subMaxOffset = this.shiftScopes[i].maxOffset; + if (subMaxOffset > max) max = subMaxOffset; + } + } + return max; + } + + /* Answer the problem reporter to use for raising new problems. + * + * Note that as a side-effect, this updates the current reference context + * (unit, type or method) in case the problem handler decides it is necessary + * to abort. + */ + public ProblemReporter problemReporter() { + + return outerMostMethodScope().problemReporter(); + } + + /* + * Code responsible to request some more emulation work inside the invocation type, so as to supply + * correct synthetic arguments to any allocation of the target type. + */ + public void propagateInnerEmulation(ReferenceBinding targetType, boolean isEnclosingInstanceSupplied) { + + // no need to propagate enclosing instances, they got eagerly allocated already. + + SyntheticArgumentBinding[] syntheticArguments; + if ((syntheticArguments = targetType.syntheticOuterLocalVariables()) != null) { + for (int i = 0, max = syntheticArguments.length; i < max; i++) { + SyntheticArgumentBinding syntheticArg = syntheticArguments[i]; + // need to filter out the one that could match a supplied enclosing instance + if (!(isEnclosingInstanceSupplied + && (syntheticArg.type == targetType.enclosingType()))) { + this.emulateOuterAccess(syntheticArg.actualOuterLocalVariable); + } + } + } + } + + /* Answer the reference type of this scope. + * + * It is the nearest enclosing type of this scope. + */ + public TypeDeclaration referenceType() { + + return methodScope().referenceType(); + } + + /* + * Answer the index of this scope relatively to its parent. + * For method scope, answers -1 (not a classScope relative position) + */ + public int scopeIndex() { + if (this instanceof MethodScope) return -1; + BlockScope parentScope = (BlockScope)parent; + Scope[] parentSubscopes = parentScope.subscopes; + for (int i = 0, max = parentScope.subscopeCount; i < max; i++) { + if (parentSubscopes[i] == this) return i; + } + return -1; + } + + // start position in this scope - for ordering scopes vs. variables + int startIndex() { + return startIndex; + } + + public String toString() { + return toString(0); + } + + public String toString(int tab) { + + String s = basicToString(tab); + for (int i = 0; i < subscopeCount; i++) + if (subscopes[i] instanceof BlockScope) + s += ((BlockScope) subscopes[i]).toString(tab + 1) + "\n"; //$NON-NLS-1$ + return s; + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java new file mode 100644 index 0000000..6d83943 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java @@ -0,0 +1,921 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.Clinit; +import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; +import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; +import org.eclipse.jdt.internal.compiler.ast.TypeReference; +import org.eclipse.jdt.internal.compiler.problem.AbortCompilation; +import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; +import org.eclipse.jdt.internal.compiler.util.HashtableOfObject; + +public class ClassScope extends Scope { + public TypeDeclaration referenceContext; + + private final static char[] IncompleteHierarchy = new char[] {'h', 'a', 's', ' ', 'i', 'n', 'c', 'o', 'n', 's', 'i', 's', 't', 'e', 'n', 't', ' ', 'h', 'i', 'e', 'r', 'a', 'r', 'c', 'h', 'y'}; + + public ClassScope(Scope parent, TypeDeclaration context) { + super(CLASS_SCOPE, parent); + this.referenceContext = context; + } + + void buildAnonymousTypeBinding(SourceTypeBinding enclosingType, ReferenceBinding supertype) { + + LocalTypeBinding anonymousType = buildLocalType(enclosingType, enclosingType.fPackage); + + SourceTypeBinding sourceType = referenceContext.binding; + if (supertype.isInterface()) { + sourceType.superclass = getJavaLangObject(); + sourceType.superInterfaces = new ReferenceBinding[] { supertype }; + } else { + sourceType.superclass = supertype; + sourceType.superInterfaces = TypeConstants.NoSuperInterfaces; + } + connectMemberTypes(); + buildFieldsAndMethods(); + anonymousType.faultInTypesForFieldsAndMethods(); + sourceType.verifyMethods(environment().methodVerifier()); + } + + private void buildFields() { + boolean hierarchyIsInconsistent = referenceContext.binding.isHierarchyInconsistent(); + if (referenceContext.fields == null) { + if (hierarchyIsInconsistent) { // 72468 + referenceContext.binding.fields = new FieldBinding[1]; + referenceContext.binding.fields[0] = + new FieldBinding(IncompleteHierarchy, VoidBinding, AccPrivate, referenceContext.binding, null); + } else { + referenceContext.binding.fields = NoFields; + } + return; + } + // count the number of fields vs. initializers + FieldDeclaration[] fields = referenceContext.fields; + int size = fields.length; + int count = 0; + for (int i = 0; i < size; i++) + if (fields[i].isField()) + count++; + + if (hierarchyIsInconsistent) + count++; + // iterate the field declarations to create the bindings, lose all duplicates + FieldBinding[] fieldBindings = new FieldBinding[count]; + HashtableOfObject knownFieldNames = new HashtableOfObject(count); + boolean duplicate = false; + count = 0; + for (int i = 0; i < size; i++) { + FieldDeclaration field = fields[i]; + if (!field.isField()) { + if (referenceContext.binding.isInterface()) + problemReporter().interfaceCannotHaveInitializers(referenceContext.binding, field); + } else { + FieldBinding fieldBinding = new FieldBinding(field, null, field.modifiers | AccUnresolved, referenceContext.binding); + // field's type will be resolved when needed for top level types + checkAndSetModifiersForField(fieldBinding, field); + + if (knownFieldNames.containsKey(field.name)) { + duplicate = true; + FieldBinding previousBinding = (FieldBinding) knownFieldNames.get(field.name); + if (previousBinding != null) { + for (int f = 0; f < i; f++) { + FieldDeclaration previousField = fields[f]; + if (previousField.binding == previousBinding) { + problemReporter().duplicateFieldInType(referenceContext.binding, previousField); + previousField.binding = null; + break; + } + } + } + knownFieldNames.put(field.name, null); // ensure that the duplicate field is found & removed + problemReporter().duplicateFieldInType(referenceContext.binding, field); + field.binding = null; + } else { + knownFieldNames.put(field.name, fieldBinding); + // remember that we have seen a field with this name + if (fieldBinding != null) + fieldBindings[count++] = fieldBinding; + } + } + } + // remove duplicate fields + if (duplicate) { + FieldBinding[] newFieldBindings = new FieldBinding[knownFieldNames.size() - 1]; + // we know we'll be removing at least 1 duplicate name + size = count; + count = 0; + for (int i = 0; i < size; i++) { + FieldBinding fieldBinding = fieldBindings[i]; + if (knownFieldNames.get(fieldBinding.name) != null) + newFieldBindings[count++] = fieldBinding; + } + fieldBindings = newFieldBindings; + } + if (hierarchyIsInconsistent) + fieldBindings[count++] = new FieldBinding(IncompleteHierarchy, VoidBinding, AccPrivate, referenceContext.binding, null); + + if (count != fieldBindings.length) + System.arraycopy(fieldBindings, 0, fieldBindings = new FieldBinding[count], 0, count); + for (int i = 0; i < count; i++) + fieldBindings[i].id = i; + referenceContext.binding.fields = fieldBindings; + } + + void buildFieldsAndMethods() { + buildFields(); + buildMethods(); + + SourceTypeBinding sourceType = referenceContext.binding; + if (sourceType.isMemberType() && !sourceType.isLocalType()) + ((MemberTypeBinding) sourceType).checkSyntheticArgsAndFields(); + + ReferenceBinding[] memberTypes = sourceType.memberTypes; + for (int i = 0, length = memberTypes.length; i < length; i++) + ((SourceTypeBinding) memberTypes[i]).scope.buildFieldsAndMethods(); + } + + private LocalTypeBinding buildLocalType( + SourceTypeBinding enclosingType, + PackageBinding packageBinding) { + + referenceContext.scope = this; + referenceContext.staticInitializerScope = new MethodScope(this, referenceContext, true); + referenceContext.initializerScope = new MethodScope(this, referenceContext, false); + + // build the binding or the local type + LocalTypeBinding localType = new LocalTypeBinding(this, enclosingType, this.switchCase()); + referenceContext.binding = localType; + checkAndSetModifiers(); + + // Look at member types + ReferenceBinding[] memberTypeBindings = NoMemberTypes; + if (referenceContext.memberTypes != null) { + int size = referenceContext.memberTypes.length; + memberTypeBindings = new ReferenceBinding[size]; + int count = 0; + nextMember : for (int i = 0; i < size; i++) { + TypeDeclaration memberContext = referenceContext.memberTypes[i]; + if (memberContext.isInterface()) { + problemReporter().nestedClassCannotDeclareInterface(memberContext); + continue nextMember; + } + ReferenceBinding type = localType; + // check that the member does not conflict with an enclosing type + do { + if (CharOperation.equals(type.sourceName, memberContext.name)) { + problemReporter().hidingEnclosingType(memberContext); + continue nextMember; + } + type = type.enclosingType(); + } while (type != null); + // check the member type does not conflict with another sibling member type + for (int j = 0; j < i; j++) { + if (CharOperation.equals(referenceContext.memberTypes[j].name, memberContext.name)) { + problemReporter().duplicateNestedType(memberContext); + continue nextMember; + } + } + + ClassScope memberScope = new ClassScope(this, referenceContext.memberTypes[i]); + LocalTypeBinding memberBinding = memberScope.buildLocalType(localType, packageBinding); + memberBinding.setAsMemberType(); + memberTypeBindings[count++] = memberBinding; + } + if (count != size) + System.arraycopy(memberTypeBindings, 0, memberTypeBindings = new ReferenceBinding[count], 0, count); + } + localType.memberTypes = memberTypeBindings; + return localType; + } + + void buildLocalTypeBinding(SourceTypeBinding enclosingType) { + + LocalTypeBinding localType = buildLocalType(enclosingType, enclosingType.fPackage); + connectTypeHierarchy(); + buildFieldsAndMethods(); + localType.faultInTypesForFieldsAndMethods(); + + referenceContext.binding.verifyMethods(environment().methodVerifier()); + } + + private void buildMethods() { + if (referenceContext.methods == null) { + referenceContext.binding.methods = NoMethods; + return; + } + + // iterate the method declarations to create the bindings + AbstractMethodDeclaration[] methods = referenceContext.methods; + int size = methods.length; + int clinitIndex = -1; + for (int i = 0; i < size; i++) { + if (methods[i] instanceof Clinit) { + clinitIndex = i; + break; + } + } + MethodBinding[] methodBindings = new MethodBinding[clinitIndex == -1 ? size : size - 1]; + + int count = 0; + for (int i = 0; i < size; i++) { + if (i != clinitIndex) { + MethodScope scope = new MethodScope(this, methods[i], false); + MethodBinding methodBinding = scope.createMethod(methods[i]); + if (methodBinding != null) // is null if binding could not be created + methodBindings[count++] = methodBinding; + } + } + if (count != methodBindings.length) + System.arraycopy(methodBindings, 0, methodBindings = new MethodBinding[count], 0, count); + + referenceContext.binding.methods = methodBindings; + referenceContext.binding.modifiers |= AccUnresolved; // until methods() is sent + } + SourceTypeBinding buildType(SourceTypeBinding enclosingType, PackageBinding packageBinding) { + // provide the typeDeclaration with needed scopes + referenceContext.scope = this; + referenceContext.staticInitializerScope = new MethodScope(this, referenceContext, true); + referenceContext.initializerScope = new MethodScope(this, referenceContext, false); + + if (enclosingType == null) { + char[][] className = CharOperation.arrayConcat(packageBinding.compoundName, referenceContext.name); + referenceContext.binding = new SourceTypeBinding(className, packageBinding, this); + } else { + char[][] className = CharOperation.deepCopy(enclosingType.compoundName); + className[className.length - 1] = + CharOperation.concat(className[className.length - 1], referenceContext.name, '$'); + referenceContext.binding = new MemberTypeBinding(className, this, enclosingType); + } + + SourceTypeBinding sourceType = referenceContext.binding; + sourceType.fPackage.addType(sourceType); + checkAndSetModifiers(); + + // Look at member types + ReferenceBinding[] memberTypeBindings = NoMemberTypes; + if (referenceContext.memberTypes != null) { + int size = referenceContext.memberTypes.length; + memberTypeBindings = new ReferenceBinding[size]; + int count = 0; + nextMember : for (int i = 0; i < size; i++) { + TypeDeclaration memberContext = referenceContext.memberTypes[i]; + if (memberContext.isInterface() + && sourceType.isNestedType() + && sourceType.isClass() + && !sourceType.isStatic()) { + problemReporter().nestedClassCannotDeclareInterface(memberContext); + continue nextMember; + } + ReferenceBinding type = sourceType; + // check that the member does not conflict with an enclosing type + do { + if (CharOperation.equals(type.sourceName, memberContext.name)) { + problemReporter().hidingEnclosingType(memberContext); + continue nextMember; + } + type = type.enclosingType(); + } while (type != null); + // check that the member type does not conflict with another sibling member type + for (int j = 0; j < i; j++) { + if (CharOperation.equals(referenceContext.memberTypes[j].name, memberContext.name)) { + problemReporter().duplicateNestedType(memberContext); + continue nextMember; + } + } + + ClassScope memberScope = new ClassScope(this, memberContext); + memberTypeBindings[count++] = memberScope.buildType(sourceType, packageBinding); + } + if (count != size) + System.arraycopy(memberTypeBindings, 0, memberTypeBindings = new ReferenceBinding[count], 0, count); + } + sourceType.memberTypes = memberTypeBindings; + return sourceType; + } + + private void checkAndSetModifiers() { + SourceTypeBinding sourceType = referenceContext.binding; + int modifiers = sourceType.modifiers; + if ((modifiers & AccAlternateModifierProblem) != 0) + problemReporter().duplicateModifierForType(sourceType); + + ReferenceBinding enclosingType = sourceType.enclosingType(); + boolean isMemberType = sourceType.isMemberType(); + + if (isMemberType) { + // checks for member types before local types to catch local members + if (enclosingType.isStrictfp()) + modifiers |= AccStrictfp; + if (enclosingType.isViewedAsDeprecated() && !sourceType.isDeprecated()) + modifiers |= AccDeprecatedImplicitly; + if (enclosingType.isInterface()) + modifiers |= AccPublic; + } else if (sourceType.isLocalType()) { + if (sourceType.isAnonymousType()) + modifiers |= AccFinal; + Scope scope = this; + do { + switch (scope.kind) { + case METHOD_SCOPE : + MethodScope methodScope = (MethodScope) scope; + if (methodScope.isInsideInitializer()) { + SourceTypeBinding type = ((TypeDeclaration) methodScope.referenceContext).binding; + + // inside field declaration ? check field modifier to see if deprecated + if (methodScope.initializedField != null) { + // currently inside this field initialization + if (methodScope.initializedField.isViewedAsDeprecated() && !sourceType.isDeprecated()){ + modifiers |= AccDeprecatedImplicitly; + } + } else { + if (type.isStrictfp()) + modifiers |= AccStrictfp; + if (type.isViewedAsDeprecated() && !sourceType.isDeprecated()) + modifiers |= AccDeprecatedImplicitly; + } + } else { + MethodBinding method = ((AbstractMethodDeclaration) methodScope.referenceContext).binding; + if (method != null){ + if (method.isStrictfp()) + modifiers |= AccStrictfp; + if (method.isViewedAsDeprecated() && !sourceType.isDeprecated()) + modifiers |= AccDeprecatedImplicitly; + } + } + break; + case CLASS_SCOPE : + // local member + if (enclosingType.isStrictfp()) + modifiers |= AccStrictfp; + if (enclosingType.isViewedAsDeprecated() && !sourceType.isDeprecated()) + modifiers |= AccDeprecatedImplicitly; + break; + } + scope = scope.parent; + } while (scope != null); + } + // after this point, tests on the 16 bits reserved. + int realModifiers = modifiers & AccJustFlag; + + if ((realModifiers & AccInterface) != 0) { + // detect abnormal cases for interfaces + if (isMemberType) { + int unexpectedModifiers = + ~(AccPublic | AccPrivate | AccProtected | AccStatic | AccAbstract | AccInterface | AccStrictfp); + if ((realModifiers & unexpectedModifiers) != 0) + problemReporter().illegalModifierForMemberInterface(sourceType); + /* + } else if (sourceType.isLocalType()) { //interfaces cannot be defined inside a method + int unexpectedModifiers = ~(AccAbstract | AccInterface | AccStrictfp); + if ((realModifiers & unexpectedModifiers) != 0) + problemReporter().illegalModifierForLocalInterface(sourceType); + */ + } else { + int unexpectedModifiers = ~(AccPublic | AccAbstract | AccInterface | AccStrictfp); + if ((realModifiers & unexpectedModifiers) != 0) + problemReporter().illegalModifierForInterface(sourceType); + } + modifiers |= AccAbstract; + } else { + // detect abnormal cases for types + if (isMemberType) { // includes member types defined inside local types + int unexpectedModifiers = + ~(AccPublic | AccPrivate | AccProtected | AccStatic | AccAbstract | AccFinal | AccStrictfp); + if ((realModifiers & unexpectedModifiers) != 0) + problemReporter().illegalModifierForMemberClass(sourceType); + } else if (sourceType.isLocalType()) { + int unexpectedModifiers = ~(AccAbstract | AccFinal | AccStrictfp); + if ((realModifiers & unexpectedModifiers) != 0) + problemReporter().illegalModifierForLocalClass(sourceType); + } else { + int unexpectedModifiers = ~(AccPublic | AccAbstract | AccFinal | AccStrictfp); + if ((realModifiers & unexpectedModifiers) != 0) + problemReporter().illegalModifierForClass(sourceType); + } + + // check that Final and Abstract are not set together + if ((realModifiers & (AccFinal | AccAbstract)) == (AccFinal | AccAbstract)) + problemReporter().illegalModifierCombinationFinalAbstractForClass(sourceType); + } + + if (isMemberType) { + // test visibility modifiers inconsistency, isolate the accessors bits + if (enclosingType.isInterface()) { + if ((realModifiers & (AccProtected | AccPrivate)) != 0) { + problemReporter().illegalVisibilityModifierForInterfaceMemberType(sourceType); + + // need to keep the less restrictive + if ((realModifiers & AccProtected) != 0) + modifiers ^= AccProtected; + if ((realModifiers & AccPrivate) != 0) + modifiers ^= AccPrivate; + } + } else { + int accessorBits = realModifiers & (AccPublic | AccProtected | AccPrivate); + if ((accessorBits & (accessorBits - 1)) > 1) { + problemReporter().illegalVisibilityModifierCombinationForMemberType(sourceType); + + // need to keep the less restrictive + if ((accessorBits & AccPublic) != 0) { + if ((accessorBits & AccProtected) != 0) + modifiers ^= AccProtected; + if ((accessorBits & AccPrivate) != 0) + modifiers ^= AccPrivate; + } + if ((accessorBits & AccProtected) != 0) + if ((accessorBits & AccPrivate) != 0) + modifiers ^= AccPrivate; + } + } + + // static modifier test + if ((realModifiers & AccStatic) == 0) { + if (enclosingType.isInterface()) + modifiers |= AccStatic; + } else { + if (!enclosingType.isStatic()) + // error the enclosing type of a static field must be static or a top-level type + problemReporter().illegalStaticModifierForMemberType(sourceType); + } + } + + sourceType.modifiers = modifiers; + } + + /* This method checks the modifiers of a field. + * + * 9.3 & 8.3 + * Need to integrate the check for the final modifiers for nested types + * + * Note : A scope is accessible by : fieldBinding.declaringClass.scope + */ + private void checkAndSetModifiersForField(FieldBinding fieldBinding, FieldDeclaration fieldDecl) { + int modifiers = fieldBinding.modifiers; + if ((modifiers & AccAlternateModifierProblem) != 0) + problemReporter().duplicateModifierForField(fieldBinding.declaringClass, fieldDecl); + + if (fieldBinding.declaringClass.isInterface()) { + int expectedValue = AccPublic | AccStatic | AccFinal; + // set the modifiers + modifiers |= expectedValue; + + // and then check that they are the only ones + if ((modifiers & AccJustFlag) != expectedValue) + problemReporter().illegalModifierForInterfaceField(fieldBinding.declaringClass, fieldDecl); + fieldBinding.modifiers = modifiers; + return; + } + + // after this point, tests on the 16 bits reserved. + int realModifiers = modifiers & AccJustFlag; + int unexpectedModifiers = + ~(AccPublic | AccPrivate | AccProtected | AccFinal | AccStatic | AccTransient | AccVolatile); + if ((realModifiers & unexpectedModifiers) != 0) + problemReporter().illegalModifierForField(fieldBinding.declaringClass, fieldDecl); + + int accessorBits = realModifiers & (AccPublic | AccProtected | AccPrivate); + if ((accessorBits & (accessorBits - 1)) > 1) { + problemReporter().illegalVisibilityModifierCombinationForField( + fieldBinding.declaringClass, + fieldDecl); + + // need to keep the less restrictive + if ((accessorBits & AccPublic) != 0) { + if ((accessorBits & AccProtected) != 0) + modifiers ^= AccProtected; + if ((accessorBits & AccPrivate) != 0) + modifiers ^= AccPrivate; + } + if ((accessorBits & AccProtected) != 0) + if ((accessorBits & AccPrivate) != 0) + modifiers ^= AccPrivate; + } + + if ((realModifiers & (AccFinal | AccVolatile)) == (AccFinal | AccVolatile)) + problemReporter().illegalModifierCombinationFinalVolatileForField( + fieldBinding.declaringClass, + fieldDecl); + + if (fieldDecl.initialization == null && (modifiers & AccFinal) != 0) { + modifiers |= AccBlankFinal; + } + fieldBinding.modifiers = modifiers; + } + + private void checkForInheritedMemberTypes(SourceTypeBinding sourceType) { + // search up the hierarchy of the sourceType to see if any superType defines a member type + // when no member types are defined, tag the sourceType & each superType with the HasNoMemberTypes bit + ReferenceBinding currentType = sourceType; + ReferenceBinding[][] interfacesToVisit = null; + int lastPosition = -1; + do { + if ((currentType.tagBits & HasNoMemberTypes) != 0) + break; // already know it has no inherited member types, can stop looking up + if (currentType.hasMemberTypes()) // avoid resolving member types eagerly + return; // has member types + ReferenceBinding[] itsInterfaces = currentType.superInterfaces(); + if (itsInterfaces != NoSuperInterfaces) { + if (interfacesToVisit == null) + interfacesToVisit = new ReferenceBinding[5][]; + if (++lastPosition == interfacesToVisit.length) + System.arraycopy( + interfacesToVisit, + 0, + interfacesToVisit = new ReferenceBinding[lastPosition * 2][], + 0, + lastPosition); + interfacesToVisit[lastPosition] = itsInterfaces; + } + } while ((currentType = currentType.superclass()) != null); + + boolean hasMembers = false; + if (interfacesToVisit != null) { + done : for (int i = 0; i <= lastPosition; i++) { + ReferenceBinding[] interfaces = interfacesToVisit[i]; + for (int j = 0, length = interfaces.length; j < length; j++) { + ReferenceBinding anInterface = interfaces[j]; + if ((anInterface.tagBits & InterfaceVisited) == 0) { // if interface as not already been visited + anInterface.tagBits |= InterfaceVisited; + if ((anInterface.tagBits & HasNoMemberTypes) != 0) + continue; // already know it has no inherited member types + if (anInterface.memberTypes() != NoMemberTypes) { + hasMembers = true; + break done; + } + + ReferenceBinding[] itsInterfaces = anInterface.superInterfaces(); + if (itsInterfaces != NoSuperInterfaces) { + if (++lastPosition == interfacesToVisit.length) + System.arraycopy( + interfacesToVisit, + 0, + interfacesToVisit = new ReferenceBinding[lastPosition * 2][], + 0, + lastPosition); + interfacesToVisit[lastPosition] = itsInterfaces; + } + } + } + } + + for (int i = 0; i <= lastPosition; i++) { + ReferenceBinding[] interfaces = interfacesToVisit[i]; + for (int j = 0, length = interfaces.length; j < length; j++) { + interfaces[j].tagBits &= ~InterfaceVisited; + if (!hasMembers) + interfaces[j].tagBits |= HasNoMemberTypes; + } + } + } + + if (!hasMembers) { + currentType = sourceType; + do { + currentType.tagBits |= HasNoMemberTypes; + } while ((currentType = currentType.superclass()) != null); + } + } + + private void connectMemberTypes() { + SourceTypeBinding sourceType = referenceContext.binding; + if (sourceType.memberTypes != NoMemberTypes) + for (int i = 0, size = sourceType.memberTypes.length; i < size; i++) + ((SourceTypeBinding) sourceType.memberTypes[i]).scope.connectTypeHierarchy(); + } + /* + Our current belief based on available JCK tests is: + inherited member types are visible as a potential superclass. + inherited interfaces are not visible when defining a superinterface. + + Error recovery story: + ensure the superclass is set to java.lang.Object if a problem is detected + resolving the superclass. + + Answer false if an error was reported against the sourceType. + */ + private boolean connectSuperclass() { + SourceTypeBinding sourceType = referenceContext.binding; + if (sourceType.id == T_Object) { // handle the case of redefining java.lang.Object up front + sourceType.superclass = null; + sourceType.superInterfaces = NoSuperInterfaces; + if (referenceContext.superclass != null || referenceContext.superInterfaces != null) + problemReporter().objectCannotHaveSuperTypes(sourceType); + return true; // do not propagate Object's hierarchy problems down to every subtype + } + if (referenceContext.superclass == null) { + sourceType.superclass = getJavaLangObject(); + return !detectCycle(sourceType, sourceType.superclass, null); + } + ReferenceBinding superclass = findSupertype(referenceContext.superclass); + if (superclass != null) { // is null if a cycle was detected cycle + referenceContext.superclass.resolvedType = superclass; // hold onto the problem type + if (!superclass.isValidBinding()) { + problemReporter().invalidSuperclass(sourceType, referenceContext.superclass, superclass); + } else if (superclass.isInterface()) { + problemReporter().superclassMustBeAClass(sourceType, referenceContext.superclass, superclass); + } else if (superclass.isFinal()) { + problemReporter().classExtendFinalClass(sourceType, referenceContext.superclass, superclass); + } else { + // only want to reach here when no errors are reported + sourceType.superclass = superclass; + return true; + } + } + sourceType.tagBits |= HierarchyHasProblems; + sourceType.superclass = getJavaLangObject(); + if ((sourceType.superclass.tagBits & BeginHierarchyCheck) == 0) + detectCycle(sourceType, sourceType.superclass, null); + return false; // reported some error against the source type + } + + /* + Our current belief based on available JCK 1.3 tests is: + inherited member types are visible as a potential superclass. + inherited interfaces are visible when defining a superinterface. + + Error recovery story: + ensure the superinterfaces contain only valid visible interfaces. + + Answer false if an error was reported against the sourceType. + */ + private boolean connectSuperInterfaces() { + SourceTypeBinding sourceType = referenceContext.binding; + sourceType.superInterfaces = NoSuperInterfaces; + if (referenceContext.superInterfaces == null) + return true; + if (sourceType.id == T_Object) // already handled the case of redefining java.lang.Object + return true; + + boolean noProblems = true; + int length = referenceContext.superInterfaces.length; + ReferenceBinding[] interfaceBindings = new ReferenceBinding[length]; + int count = 0; + nextInterface : for (int i = 0; i < length; i++) { + ReferenceBinding superInterface = findSupertype(referenceContext.superInterfaces[i]); + if (superInterface == null) { // detected cycle + noProblems = false; + continue nextInterface; + } + referenceContext.superInterfaces[i].resolvedType = superInterface; // hold onto the problem type + if (!superInterface.isValidBinding()) { + problemReporter().invalidSuperinterface( + sourceType, + referenceContext.superInterfaces[i], + superInterface); + sourceType.tagBits |= HierarchyHasProblems; + noProblems = false; + continue nextInterface; + } + // Check for a duplicate interface once the name is resolved, otherwise we may be confused (ie : a.b.I and c.d.I) + for (int k = 0; k < count; k++) { + if (interfaceBindings[k] == superInterface) { + // should this be treated as a warning? + problemReporter().duplicateSuperinterface(sourceType, referenceContext, superInterface); + continue nextInterface; + } + } + if (superInterface.isClass()) { + problemReporter().superinterfaceMustBeAnInterface(sourceType, referenceContext, superInterface); + sourceType.tagBits |= HierarchyHasProblems; + noProblems = false; + continue nextInterface; + } + + // only want to reach here when no errors are reported + interfaceBindings[count++] = superInterface; + } + // hold onto all correctly resolved superinterfaces + if (count > 0) { + if (count != length) + System.arraycopy(interfaceBindings, 0, interfaceBindings = new ReferenceBinding[count], 0, count); + sourceType.superInterfaces = interfaceBindings; + } + return noProblems; + } + + void connectTypeHierarchy() { + SourceTypeBinding sourceType = referenceContext.binding; + if ((sourceType.tagBits & BeginHierarchyCheck) == 0) { + boolean noProblems = true; + sourceType.tagBits |= BeginHierarchyCheck; + if (sourceType.isClass()) + noProblems &= connectSuperclass(); + noProblems &= connectSuperInterfaces(); + sourceType.tagBits |= EndHierarchyCheck; + if (noProblems && sourceType.isHierarchyInconsistent()) + problemReporter().hierarchyHasProblems(sourceType); + } + connectMemberTypes(); + try { + checkForInheritedMemberTypes(sourceType); + } catch (AbortCompilation e) { + e.updateContext(referenceContext, referenceCompilationUnit().compilationResult); + throw e; + } + } + + private void connectTypeHierarchyWithoutMembers() { + // must ensure the imports are resolved + if (parent instanceof CompilationUnitScope) { + if (((CompilationUnitScope) parent).imports == null) + ((CompilationUnitScope) parent).checkAndSetImports(); + } else if (parent instanceof ClassScope) { + // ensure that the enclosing type has already been checked + ((ClassScope) parent).connectTypeHierarchyWithoutMembers(); + } + + // double check that the hierarchy search has not already begun... + SourceTypeBinding sourceType = referenceContext.binding; + if ((sourceType.tagBits & BeginHierarchyCheck) != 0) + return; + + boolean noProblems = true; + sourceType.tagBits |= BeginHierarchyCheck; + if (sourceType.isClass()) + noProblems &= connectSuperclass(); + noProblems &= connectSuperInterfaces(); + sourceType.tagBits |= EndHierarchyCheck; + if (noProblems && sourceType.isHierarchyInconsistent()) + problemReporter().hierarchyHasProblems(sourceType); + } + + // Answer whether a cycle was found between the sourceType & the superType + private boolean detectCycle( + SourceTypeBinding sourceType, + ReferenceBinding superType, + TypeReference reference) { + if (sourceType == superType) { + problemReporter().hierarchyCircularity(sourceType, superType, reference); + sourceType.tagBits |= HierarchyHasProblems; + return true; + } + + if (superType.isBinaryBinding()) { + // force its superclass & superinterfaces to be found... 2 possibilities exist - the source type is included in the hierarchy of: + // - a binary type... this case MUST be caught & reported here + // - another source type... this case is reported against the other source type + boolean hasCycle = false; + if (superType.superclass() != null) { + if (sourceType == superType.superclass()) { + problemReporter().hierarchyCircularity(sourceType, superType, reference); + sourceType.tagBits |= HierarchyHasProblems; + superType.tagBits |= HierarchyHasProblems; + return true; + } + hasCycle |= detectCycle(sourceType, superType.superclass(), reference); + if ((superType.superclass().tagBits & HierarchyHasProblems) != 0) { + sourceType.tagBits |= HierarchyHasProblems; + superType.tagBits |= HierarchyHasProblems; // propagate down the hierarchy + } + } + + ReferenceBinding[] itsInterfaces = superType.superInterfaces(); + if (itsInterfaces != NoSuperInterfaces) { + for (int i = 0, length = itsInterfaces.length; i < length; i++) { + ReferenceBinding anInterface = itsInterfaces[i]; + if (sourceType == anInterface) { + problemReporter().hierarchyCircularity(sourceType, superType, reference); + sourceType.tagBits |= HierarchyHasProblems; + superType.tagBits |= HierarchyHasProblems; + return true; + } + hasCycle |= detectCycle(sourceType, anInterface, reference); + if ((anInterface.tagBits & HierarchyHasProblems) != 0) { + sourceType.tagBits |= HierarchyHasProblems; + superType.tagBits |= HierarchyHasProblems; + } + } + } + return hasCycle; + } + + if ((superType.tagBits & EndHierarchyCheck) == 0 + && (superType.tagBits & BeginHierarchyCheck) != 0) { + problemReporter().hierarchyCircularity(sourceType, superType, reference); + sourceType.tagBits |= HierarchyHasProblems; + superType.tagBits |= HierarchyHasProblems; + return true; + } + if ((superType.tagBits & BeginHierarchyCheck) == 0) + // ensure if this is a source superclass that it has already been checked + ((SourceTypeBinding) superType).scope.connectTypeHierarchyWithoutMembers(); + if ((superType.tagBits & HierarchyHasProblems) != 0) + sourceType.tagBits |= HierarchyHasProblems; + return false; + } + + private ReferenceBinding findSupertype(TypeReference typeReference) { + try { + typeReference.aboutToResolve(this); // allows us to trap completion & selection nodes + char[][] compoundName = typeReference.getTypeName(); + compilationUnitScope().recordQualifiedReference(compoundName); + SourceTypeBinding sourceType = referenceContext.binding; + int size = compoundName.length; + int n = 1; + ReferenceBinding superType; + + // resolve the first name of the compoundName + if (CharOperation.equals(compoundName[0], sourceType.sourceName)) { + superType = sourceType; + // match against the sourceType even though nested members cannot be supertypes + } else { + Binding typeOrPackage = parent.getTypeOrPackage(compoundName[0], TYPE | PACKAGE); + if (typeOrPackage == null || !typeOrPackage.isValidBinding()) + return new ProblemReferenceBinding( + compoundName[0], + typeOrPackage == null ? NotFound : typeOrPackage.problemId()); + + boolean checkVisibility = false; + for (; n < size; n++) { + if (!(typeOrPackage instanceof PackageBinding)) + break; + PackageBinding packageBinding = (PackageBinding) typeOrPackage; + typeOrPackage = packageBinding.getTypeOrPackage(compoundName[n]); + if (typeOrPackage == null || !typeOrPackage.isValidBinding()) + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, n + 1), + typeOrPackage == null ? NotFound : typeOrPackage.problemId()); + checkVisibility = true; + } + + // convert to a ReferenceBinding + if (typeOrPackage instanceof PackageBinding) // error, the compoundName is a packageName + return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, n), NotFound); + superType = (ReferenceBinding) typeOrPackage; + compilationUnitScope().recordTypeReference(superType); // to record supertypes + + if (checkVisibility + && n == size) { // if we're finished and know the final supertype then check visibility + if (!superType.canBeSeenBy(sourceType.fPackage)) + // its a toplevel type so just check package access + return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, n), superType, NotVisible); + } + } + // at this point we know we have a type but we have to look for cycles + while (true) { + // must detect cycles & force connection up the hierarchy... also handle cycles with binary types. + // must be guaranteed that the superType knows its entire hierarchy + if (detectCycle(sourceType, superType, typeReference)) + return null; // cycle error was already reported + + if (n >= size) + break; + + // retrieve the next member type + char[] typeName = compoundName[n++]; + superType = findMemberType(typeName, superType); + if (superType == null) + return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, n), NotFound); + if (!superType.isValidBinding()) { + superType.compoundName = CharOperation.subarray(compoundName, 0, n); + return superType; + } + } + return superType; + } catch (AbortCompilation e) { + e.updateContext(typeReference, referenceCompilationUnit().compilationResult); + throw e; + } + } + + /* Answer the problem reporter to use for raising new problems. + * + * Note that as a side-effect, this updates the current reference context + * (unit, type or method) in case the problem handler decides it is necessary + * to abort. + */ + public ProblemReporter problemReporter() { + MethodScope outerMethodScope; + if ((outerMethodScope = outerMostMethodScope()) == null) { + ProblemReporter problemReporter = referenceCompilationUnit().problemReporter; + problemReporter.referenceContext = referenceContext; + return problemReporter; + } + return outerMethodScope.problemReporter(); + } + + /* Answer the reference type of this scope. + * It is the nearest enclosing type of this scope. + */ + public TypeDeclaration referenceType() { + return referenceContext; + } + + public String toString() { + if (referenceContext != null) + return "--- Class Scope ---\n\n" //$NON-NLS-1$ + + referenceContext.binding.toString(); + return "--- Class Scope ---\n\n Binding not initialized" ; //$NON-NLS-1$ + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java new file mode 100644 index 0000000..d4a8d4f --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java @@ -0,0 +1,604 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; +import org.eclipse.jdt.internal.compiler.ast.ImportReference; +import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; +import org.eclipse.jdt.internal.compiler.util.CompoundNameVector; +import org.eclipse.jdt.internal.compiler.util.HashtableOfObject; +import org.eclipse.jdt.internal.compiler.util.HashtableOfType; +import org.eclipse.jdt.internal.compiler.util.ObjectVector; +import org.eclipse.jdt.internal.compiler.util.SimpleNameVector; + +public class CompilationUnitScope extends Scope { + + public LookupEnvironment environment; + public CompilationUnitDeclaration referenceContext; + public char[][] currentPackageName; + public PackageBinding fPackage; + public ImportBinding[] imports; + public HashtableOfObject resolvedSingeTypeImports; + + public SourceTypeBinding[] topLevelTypes; + + private CompoundNameVector qualifiedReferences; + private SimpleNameVector simpleNameReferences; + private ObjectVector referencedTypes; + + HashtableOfType constantPoolNameUsage; + +public CompilationUnitScope(CompilationUnitDeclaration unit, LookupEnvironment environment) { + super(COMPILATION_UNIT_SCOPE, null); + this.environment = environment; + this.referenceContext = unit; + unit.scope = this; + this.currentPackageName = unit.currentPackage == null ? CharOperation.NO_CHAR_CHAR : unit.currentPackage.tokens; + + if (environment.options.produceReferenceInfo) { + this.qualifiedReferences = new CompoundNameVector(); + this.simpleNameReferences = new SimpleNameVector(); + this.referencedTypes = new ObjectVector(); + } else { + this.qualifiedReferences = null; // used to test if dependencies should be recorded + this.simpleNameReferences = null; + this.referencedTypes = null; + } +} +void buildFieldsAndMethods() { + for (int i = 0, length = topLevelTypes.length; i < length; i++) + topLevelTypes[i].scope.buildFieldsAndMethods(); +} +void buildTypeBindings() { + topLevelTypes = new SourceTypeBinding[0]; // want it initialized if the package cannot be resolved + if (referenceContext.compilationResult.compilationUnit != null) { + char[][] expectedPackageName = referenceContext.compilationResult.compilationUnit.getPackageName(); + if (expectedPackageName != null + && !CharOperation.equals(currentPackageName, expectedPackageName)) { + + // only report if the unit isn't structurally empty + if (referenceContext.currentPackage != null + || referenceContext.types != null + || referenceContext.imports != null) { + problemReporter().packageIsNotExpectedPackage(referenceContext); + } + currentPackageName = expectedPackageName.length == 0 ? CharOperation.NO_CHAR_CHAR : expectedPackageName; + } + } + if (currentPackageName == CharOperation.NO_CHAR_CHAR) { + if ((fPackage = environment.defaultPackage) == null) { + problemReporter().mustSpecifyPackage(referenceContext); + return; + } + } else { + if ((fPackage = environment.createPackage(currentPackageName)) == null) { + problemReporter().packageCollidesWithType(referenceContext); + return; + } + recordQualifiedReference(currentPackageName); // always dependent on your own package + } + + // Skip typeDeclarations which know of previously reported errors + TypeDeclaration[] types = referenceContext.types; + int typeLength = (types == null) ? 0 : types.length; + topLevelTypes = new SourceTypeBinding[typeLength]; + int count = 0; + nextType: for (int i = 0; i < typeLength; i++) { + TypeDeclaration typeDecl = types[i]; + ReferenceBinding typeBinding = fPackage.getType0(typeDecl.name); + recordSimpleReference(typeDecl.name); // needed to detect collision cases + if (typeBinding != null && !(typeBinding instanceof UnresolvedReferenceBinding)) { + // if a type exists, it must be a valid type - cannot be a NotFound problem type + // unless its an unresolved type which is now being defined + problemReporter().duplicateTypes(referenceContext, typeDecl); + continue nextType; + } + if (fPackage != environment.defaultPackage && fPackage.getPackage(typeDecl.name) != null) { + // if a package exists, it must be a valid package - cannot be a NotFound problem package + problemReporter().typeCollidesWithPackage(referenceContext, typeDecl); + continue nextType; + } + + if ((typeDecl.modifiers & AccPublic) != 0) { + char[] mainTypeName; + if ((mainTypeName = referenceContext.getMainTypeName()) != null // mainTypeName == null means that implementor of ICompilationUnit decided to return null + && !CharOperation.equals(mainTypeName, typeDecl.name)) { + problemReporter().publicClassMustMatchFileName(referenceContext, typeDecl); + continue nextType; + } + } + + ClassScope child = new ClassScope(this, typeDecl); + SourceTypeBinding type = child.buildType(null, fPackage); + if(type != null) { + topLevelTypes[count++] = type; + } + } + + // shrink topLevelTypes... only happens if an error was reported + if (count != topLevelTypes.length) + System.arraycopy(topLevelTypes, 0, topLevelTypes = new SourceTypeBinding[count], 0, count); +} +void checkAndSetImports() { + if (referenceContext.imports == null) { + imports = getDefaultImports(); + return; + } + + // allocate the import array, add java.lang.* by default + int numberOfStatements = referenceContext.imports.length; + int numberOfImports = numberOfStatements + 1; + for (int i = 0; i < numberOfStatements; i++) { + ImportReference importReference = referenceContext.imports[i]; + if (importReference.onDemand && CharOperation.equals(JAVA_LANG, importReference.tokens)) { + numberOfImports--; + break; + } + } + ImportBinding[] resolvedImports = new ImportBinding[numberOfImports]; + resolvedImports[0] = getDefaultImports()[0]; + int index = 1; + + nextImport : for (int i = 0; i < numberOfStatements; i++) { + ImportReference importReference = referenceContext.imports[i]; + char[][] compoundName = importReference.tokens; + + // skip duplicates or imports of the current package + for (int j = 0; j < index; j++) + if (resolvedImports[j].onDemand == importReference.onDemand) + if (CharOperation.equals(compoundName, resolvedImports[j].compoundName)) + continue nextImport; + if (importReference.onDemand == true) + if (CharOperation.equals(compoundName, currentPackageName)) + continue nextImport; + + if (importReference.onDemand) { + Binding importBinding = findOnDemandImport(compoundName); + if (!importBinding.isValidBinding()) + continue nextImport; // we report all problems in faultInImports() + resolvedImports[index++] = new ImportBinding(compoundName, true, importBinding, importReference); + } else { + resolvedImports[index++] = new ImportBinding(compoundName, false, null, importReference); + } + } + + // shrink resolvedImports... only happens if an error was reported + if (resolvedImports.length > index) + System.arraycopy(resolvedImports, 0, resolvedImports = new ImportBinding[index], 0, index); + imports = resolvedImports; +} +/* + * INTERNAL USE-ONLY + * Innerclasses get their name computed as they are generated, since some may not + * be actually outputed if sitting inside unreachable code. + */ +public char[] computeConstantPoolName(LocalTypeBinding localType) { + if (localType.constantPoolName() != null) { + return localType.constantPoolName(); + } + // delegates to the outermost enclosing classfile, since it is the only one with a global vision of its innertypes. + + if (constantPoolNameUsage == null) + constantPoolNameUsage = new HashtableOfType(); + + ReferenceBinding outerMostEnclosingType = localType.scope.outerMostClassScope().enclosingSourceType(); + + // ensure there is not already such a local type name defined by the user + int index = 0; + char[] candidateName; + while(true) { + if (localType.isMemberType()){ + if (index == 0){ + candidateName = CharOperation.concat( + localType.enclosingType().constantPoolName(), + localType.sourceName, + '$'); + } else { + // in case of collision, then member name gets extra $1 inserted + // e.g. class X { { class L{} new X(){ class L{} } } } + candidateName = CharOperation.concat( + localType.enclosingType().constantPoolName(), + '$', + String.valueOf(index).toCharArray(), + '$', + localType.sourceName); + } + } else if (localType.isAnonymousType()){ + candidateName = CharOperation.concat( + outerMostEnclosingType.constantPoolName(), + String.valueOf(index+1).toCharArray(), + '$'); + } else { + candidateName = CharOperation.concat( + outerMostEnclosingType.constantPoolName(), + '$', + String.valueOf(index+1).toCharArray(), + '$', + localType.sourceName); + } + if (constantPoolNameUsage.get(candidateName) != null) { + index ++; + } else { + constantPoolNameUsage.put(candidateName, localType); + break; + } + } + return candidateName; +} + +void connectTypeHierarchy() { + for (int i = 0, length = topLevelTypes.length; i < length; i++) + topLevelTypes[i].scope.connectTypeHierarchy(); +} +void faultInImports() { + if (referenceContext.imports == null) + return; + + // collect the top level type names if a single type import exists + int numberOfStatements = referenceContext.imports.length; + HashtableOfType typesBySimpleNames = null; + for (int i = 0; i < numberOfStatements; i++) { + if (!referenceContext.imports[i].onDemand) { + typesBySimpleNames = new HashtableOfType(topLevelTypes.length + numberOfStatements); + for (int j = 0, length = topLevelTypes.length; j < length; j++) + typesBySimpleNames.put(topLevelTypes[j].sourceName, topLevelTypes[j]); + break; + } + } + + // allocate the import array, add java.lang.* by default + int numberOfImports = numberOfStatements + 1; + for (int i = 0; i < numberOfStatements; i++) { + ImportReference importReference = referenceContext.imports[i]; + if (importReference.onDemand && CharOperation.equals(JAVA_LANG, importReference.tokens)) { + numberOfImports--; + break; + } + } + ImportBinding[] resolvedImports = new ImportBinding[numberOfImports]; + resolvedImports[0] = getDefaultImports()[0]; + int index = 1; + + nextImport : for (int i = 0; i < numberOfStatements; i++) { + ImportReference importReference = referenceContext.imports[i]; + char[][] compoundName = importReference.tokens; + + // skip duplicates or imports of the current package + for (int j = 0; j < index; j++) + if (resolvedImports[j].onDemand == importReference.onDemand) + if (CharOperation.equals(compoundName, resolvedImports[j].compoundName)) { + problemReporter().unusedImport(importReference); // since skipped, must be reported now + continue nextImport; + } + if (importReference.onDemand == true) + if (CharOperation.equals(compoundName, currentPackageName)) { + problemReporter().unusedImport(importReference); // since skipped, must be reported now + continue nextImport; + } + if (importReference.onDemand) { + Binding importBinding = findOnDemandImport(compoundName); + if (!importBinding.isValidBinding()) { + problemReporter().importProblem(importReference, importBinding); + continue nextImport; + } + resolvedImports[index++] = new ImportBinding(compoundName, true, importBinding, importReference); + } else { + Binding typeBinding = findSingleTypeImport(compoundName); + if (!typeBinding.isValidBinding()) { + problemReporter().importProblem(importReference, typeBinding); + continue nextImport; + } + if (typeBinding instanceof PackageBinding) { + problemReporter().cannotImportPackage(importReference); + continue nextImport; + } + if (typeBinding instanceof ReferenceBinding) { + ReferenceBinding referenceBinding = (ReferenceBinding) typeBinding; + if (importReference.isTypeUseDeprecated(referenceBinding, this)) { + problemReporter().deprecatedType((TypeBinding) typeBinding, importReference); + } + } + ReferenceBinding existingType = typesBySimpleNames.get(compoundName[compoundName.length - 1]); + if (existingType != null) { + // duplicate test above should have caught this case, but make sure + if (existingType == typeBinding) { + continue nextImport; + } + // either the type collides with a top level type or another imported type + for (int j = 0, length = topLevelTypes.length; j < length; j++) { + if (CharOperation.equals(topLevelTypes[j].sourceName, existingType.sourceName)) { + problemReporter().conflictingImport(importReference); + continue nextImport; + } + } + problemReporter().duplicateImport(importReference); + continue nextImport; + } + resolvedImports[index++] = new ImportBinding(compoundName, false, typeBinding, importReference); + typesBySimpleNames.put(compoundName[compoundName.length - 1], (ReferenceBinding) typeBinding); + } + } + + // shrink resolvedImports... only happens if an error was reported + if (resolvedImports.length > index) + System.arraycopy(resolvedImports, 0, resolvedImports = new ImportBinding[index], 0, index); + imports = resolvedImports; + + int length = imports.length; + resolvedSingeTypeImports = new HashtableOfObject(length); + for (int i = 0; i < length; i++) { + ImportBinding binding = imports[i]; + if (!binding.onDemand) + resolvedSingeTypeImports.put(binding.compoundName[binding.compoundName.length - 1], binding); + } +} +public void faultInTypes() { + faultInImports(); + + for (int i = 0, length = topLevelTypes.length; i < length; i++) + topLevelTypes[i].faultInTypesForFieldsAndMethods(); +} +private Binding findOnDemandImport(char[][] compoundName) { + recordQualifiedReference(compoundName); + + Binding binding = environment.getTopLevelPackage(compoundName[0]); + int i = 1; + int length = compoundName.length; + foundNothingOrType: if (binding != null) { + PackageBinding packageBinding = (PackageBinding) binding; + while (i < length) { + binding = packageBinding.getTypeOrPackage(compoundName[i++]); + if (binding == null || !binding.isValidBinding()) { + binding = null; + break foundNothingOrType; + } + if (!(binding instanceof PackageBinding)) + break foundNothingOrType; + + packageBinding = (PackageBinding) binding; + } + return packageBinding; + } + + ReferenceBinding type; + if (binding == null) { + if (environment.defaultPackage == null + || environment.options.complianceLevel >= ClassFileConstants.JDK1_4){ + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, i), + NotFound); + } + type = findType(compoundName[0], environment.defaultPackage, environment.defaultPackage); + if (type == null || !type.isValidBinding()) + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, i), + NotFound); + i = 1; // reset to look for member types inside the default package type + } else { + type = (ReferenceBinding) binding; + } + + for (; i < length; i++) { + if (!type.canBeSeenBy(fPackage)) { + return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, i), type, NotVisible); + } + // does not look for inherited member types on purpose + if ((type = type.getMemberType(compoundName[i])) == null) { + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, i + 1), + NotFound); + } + } + if (!type.canBeSeenBy(fPackage)) + return new ProblemReferenceBinding(compoundName, type, NotVisible); + return type; +} +private Binding findSingleTypeImport(char[][] compoundName) { + if (compoundName.length == 1) { + // findType records the reference + // the name cannot be a package + if (environment.defaultPackage == null + || environment.options.complianceLevel >= ClassFileConstants.JDK1_4) + return new ProblemReferenceBinding(compoundName, NotFound); + ReferenceBinding typeBinding = findType(compoundName[0], environment.defaultPackage, fPackage); + if (typeBinding == null) + return new ProblemReferenceBinding(compoundName, NotFound); + return typeBinding; + } + return findOnDemandImport(compoundName); +} +ImportBinding[] getDefaultImports() { + // initialize the default imports if necessary... share the default java.lang.* import + if (environment.defaultImports != null) return environment.defaultImports; + + Binding importBinding = environment.getTopLevelPackage(JAVA); + if (importBinding != null) + importBinding = ((PackageBinding) importBinding).getTypeOrPackage(JAVA_LANG[1]); + + // abort if java.lang cannot be found... + if (importBinding == null || !importBinding.isValidBinding()) + problemReporter().isClassPathCorrect(JAVA_LANG_OBJECT, referenceCompilationUnit()); + + return environment.defaultImports = new ImportBinding[] {new ImportBinding(JAVA_LANG, true, importBinding, null)}; +} +/* Answer the problem reporter to use for raising new problems. +* +* Note that as a side-effect, this updates the current reference context +* (unit, type or method) in case the problem handler decides it is necessary +* to abort. +*/ + +public ProblemReporter problemReporter() { + ProblemReporter problemReporter = referenceContext.problemReporter; + problemReporter.referenceContext = referenceContext; + return problemReporter; +} + +/* +What do we hold onto: + +1. when we resolve 'a.b.c', say we keep only 'a.b.c' + & when we fail to resolve 'c' in 'a.b', lets keep 'a.b.c' +THEN when we come across a new/changed/removed item named 'a.b.c', + we would find all references to 'a.b.c' +-> This approach fails because every type is resolved in every onDemand import to + detect collision cases... so the references could be 10 times bigger than necessary. + +2. when we resolve 'a.b.c', lets keep 'a.b' & 'c' + & when we fail to resolve 'c' in 'a.b', lets keep 'a.b' & 'c' +THEN when we come across a new/changed/removed item named 'a.b.c', + we would find all references to 'a.b' & 'c' +-> This approach does not have a space problem but fails to handle collision cases. + What happens if a type is added named 'a.b'? We would search for 'a' & 'b' but + would not find a match. + +3. when we resolve 'a.b.c', lets keep 'a', 'a.b' & 'a', 'b', 'c' + & when we fail to resolve 'c' in 'a.b', lets keep 'a', 'a.b' & 'a', 'b', 'c' +THEN when we come across a new/changed/removed item named 'a.b.c', + we would find all references to 'a.b' & 'c' +OR 'a.b' -> 'a' & 'b' +OR 'a' -> '' & 'a' +-> As long as each single char[] is interned, we should not have a space problem + and can handle collision cases. + +4. when we resolve 'a.b.c', lets keep 'a.b' & 'a', 'b', 'c' + & when we fail to resolve 'c' in 'a.b', lets keep 'a.b' & 'a', 'b', 'c' +THEN when we come across a new/changed/removed item named 'a.b.c', + we would find all references to 'a.b' & 'c' +OR 'a.b' -> 'a' & 'b' in the simple name collection +OR 'a' -> 'a' in the simple name collection +-> As long as each single char[] is interned, we should not have a space problem + and can handle collision cases. +*/ +void recordQualifiedReference(char[][] qualifiedName) { + if (qualifiedReferences == null) return; // not recording dependencies + + int length = qualifiedName.length; + if (length > 1) { + while (!qualifiedReferences.contains(qualifiedName)) { + qualifiedReferences.add(qualifiedName); + if (length == 2) { + recordSimpleReference(qualifiedName[0]); + recordSimpleReference(qualifiedName[1]); + return; + } + length--; + recordSimpleReference(qualifiedName[length]); + System.arraycopy(qualifiedName, 0, qualifiedName = new char[length][], 0, length); + } + } else if (length == 1) { + recordSimpleReference(qualifiedName[0]); + } +} +void recordReference(char[][] qualifiedEnclosingName, char[] simpleName) { + recordQualifiedReference(qualifiedEnclosingName); + recordSimpleReference(simpleName); +} +void recordSimpleReference(char[] simpleName) { + if (simpleNameReferences == null) return; // not recording dependencies + + if (!simpleNameReferences.contains(simpleName)) + simpleNameReferences.add(simpleName); +} +void recordTypeReference(TypeBinding type) { + if (referencedTypes == null) return; // not recording dependencies + + if (type.isArrayType()) + type = ((ArrayBinding) type).leafComponentType; + + if (type.isBaseType()) return; + if (referencedTypes.containsIdentical(type)) return; + if (((ReferenceBinding) type).isLocalType()) return; + + referencedTypes.add(type); +} +void recordTypeReferences(TypeBinding[] types) { + if (qualifiedReferences == null) return; // not recording dependencies + if (types == null || types.length == 0) return; + + for (int i = 0, max = types.length; i < max; i++) { + // No need to record supertypes of method arguments & thrown exceptions, just the compoundName + // If a field/method is retrieved from such a type then a separate call does the job + TypeBinding type = types[i]; + if (type.isArrayType()) + type = ((ArrayBinding) type).leafComponentType; + if (!type.isBaseType()) { + ReferenceBinding actualType = (ReferenceBinding) type; + if (!actualType.isLocalType()) + recordQualifiedReference(actualType.isMemberType() + ? CharOperation.splitOn('.', actualType.readableName()) + : actualType.compoundName); + } + } +} +Binding resolveSingleTypeImport(ImportBinding importBinding) { + if (importBinding.resolvedImport == null) { + importBinding.resolvedImport = findSingleTypeImport(importBinding.compoundName); + if (!importBinding.resolvedImport.isValidBinding() || importBinding.resolvedImport instanceof PackageBinding) { + if (this.imports != null){ + ImportBinding[] newImports = new ImportBinding[imports.length - 1]; + for (int i = 0, n = 0, max = this.imports.length; i < max; i++) + if (this.imports[i] != importBinding){ + newImports[n++] = this.imports[i]; + } + this.imports = newImports; + } + return null; + } + } + return importBinding.resolvedImport; +} +public void storeDependencyInfo() { + // add the type hierarchy of each referenced type + // cannot do early since the hierarchy may not be fully resolved + for (int i = 0; i < referencedTypes.size; i++) { // grows as more types are added + ReferenceBinding type = (ReferenceBinding) referencedTypes.elementAt(i); + if (!type.isLocalType()) { + recordQualifiedReference(type.isMemberType() + ? CharOperation.splitOn('.', type.readableName()) + : type.compoundName); + ReferenceBinding enclosing = type.enclosingType(); + if (enclosing != null && !referencedTypes.containsIdentical(enclosing)) + referencedTypes.add(enclosing); // to record its supertypes + } + ReferenceBinding superclass = type.superclass(); + if (superclass != null && !referencedTypes.containsIdentical(superclass)) + referencedTypes.add(superclass); // to record its supertypes + ReferenceBinding[] interfaces = type.superInterfaces(); + if (interfaces != null && interfaces.length > 0) + for (int j = 0, length = interfaces.length; j < length; j++) + if (!referencedTypes.containsIdentical(interfaces[j])) + referencedTypes.add(interfaces[j]); // to record its supertypes + } + + int size = qualifiedReferences.size; + char[][][] qualifiedRefs = new char[size][][]; + for (int i = 0; i < size; i++) + qualifiedRefs[i] = qualifiedReferences.elementAt(i); + referenceContext.compilationResult.qualifiedReferences = qualifiedRefs; + + size = simpleNameReferences.size; + char[][] simpleRefs = new char[size][]; + for (int i = 0; i < size; i++) + simpleRefs[i] = simpleNameReferences.elementAt(i); + referenceContext.compilationResult.simpleNameReferences = simpleRefs; +} +public String toString() { + return "--- CompilationUnit Scope : " + new String(referenceContext.getFileName()); //$NON-NLS-1$ +} +public void verifyMethods(MethodVerifier verifier) { + for (int i = 0, length = topLevelTypes.length; i < length; i++) + topLevelTypes[i].verifyMethods(verifier); +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/CompilerModifiers.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/CompilerModifiers.java new file mode 100644 index 0000000..31f21cc --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/CompilerModifiers.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; + +public interface CompilerModifiers extends ClassFileConstants { // modifier constant + // those constants are depending upon ClassFileConstants (relying that classfiles only use the 16 lower bits) + final int AccDefault = 0; + final int AccJustFlag = 0xFFFF; + final int AccCatchesExceptions = 0x10000; // bit17 + final int AccThrowsExceptions = 0x20000; // bit18 - also IConstants.AccSynthetic + final int AccProblem = 0x40000; // bit19 + final int AccFromClassFile = 0x80000; // bit20 + final int AccIsConstantValue = 0x80000; // bit20 + final int AccDefaultAbstract = 0x80000; // bit20 + // bit21 - IConstants.AccDeprecated + final int AccDeprecatedImplicitly = 0x200000; // bit22 to record whether deprecated itself or contained by a deprecated type + final int AccAlternateModifierProblem = 0x400000; // bit23 + final int AccModifierProblem = 0x800000; // bit24 + final int AccSemicolonBody = 0x1000000; // bit25 + final int AccUnresolved = 0x2000000; // bit26 + final int AccClearPrivateModifier = 0x4000000; // bit27 might be requested during private access emulation + final int AccBlankFinal = 0x4000000; // bit27 for blank final variables + final int AccIsDefaultConstructor = 0x4000000; // bit27 for default constructor + final int AccPrivateUsed = 0x8000000; // bit28 used to diagnose unused private members + final int AccVisibilityMASK = AccPublic | AccProtected | AccPrivate; + + final int AccOverriding = 0x10000000; // bit29 to record fact a method overrides another one + final int AccImplementing = 0x20000000; // bit30 to record fact a method implements another one (it is concrete and overrides an abstract one) +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java new file mode 100644 index 0000000..4889096 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java @@ -0,0 +1,210 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; +import org.eclipse.jdt.internal.compiler.impl.Constant; + +public class FieldBinding extends VariableBinding { + public ReferenceBinding declaringClass; +protected FieldBinding() { + // for creating problem field +} +public FieldBinding(char[] name, TypeBinding type, int modifiers, ReferenceBinding declaringClass, Constant constant) { + this.modifiers = modifiers; + this.type = type; + this.name = name; + this.declaringClass = declaringClass; + this.constant = constant; + + // propagate the deprecated modifier + if (this.declaringClass != null) + if (this.declaringClass.isViewedAsDeprecated() && !isDeprecated()) + this.modifiers |= AccDeprecatedImplicitly; +} +public FieldBinding(FieldDeclaration field, TypeBinding type, int modifiers, ReferenceBinding declaringClass) { + this(field.name, type, modifiers, declaringClass, null); + field.binding = this; // record binding in declaration +} +// special API used to change field declaring class for runtime visibility check +public FieldBinding(FieldBinding initialFieldBinding, ReferenceBinding declaringClass) { + this.modifiers = initialFieldBinding.modifiers; + this.type = initialFieldBinding.type; + this.name = initialFieldBinding.name; + this.declaringClass = declaringClass; + this.constant = initialFieldBinding.constant; + this.id = initialFieldBinding.id; +} +/* API +* Answer the receiver's binding type from Binding.BindingID. +*/ + +public final int bindingType() { + return FIELD; +} +/* Answer true if the receiver is visible to the type provided by the scope. +* InvocationSite implements isSuperAccess() to provide additional information +* if the receiver is protected. +* +* NOTE: Cannot invoke this method with a compilation unit scope. +*/ + +public final boolean canBeSeenBy(TypeBinding receiverType, InvocationSite invocationSite, Scope scope) { + if (isPublic()) return true; + + SourceTypeBinding invocationType = scope.enclosingSourceType(); + if (invocationType == declaringClass && invocationType == receiverType) return true; + + if (isProtected()) { + // answer true if the invocationType is the declaringClass or they are in the same package + // OR the invocationType is a subclass of the declaringClass + // AND the receiverType is the invocationType or its subclass + // OR the method is a static method accessed directly through a type + // OR previous assertions are true for one of the enclosing type + if (invocationType == declaringClass) return true; + if (invocationType.fPackage == declaringClass.fPackage) return true; + + ReferenceBinding currentType = invocationType; + int depth = 0; + do { + if (declaringClass.isSuperclassOf(currentType)) { + if (invocationSite.isSuperAccess()){ + return true; + } + // receiverType can be an array binding in one case... see if you can change it + if (receiverType instanceof ArrayBinding){ + return false; + } + if (isStatic()){ + if (depth > 0) invocationSite.setDepth(depth); + return true; // see 1FMEPDL - return invocationSite.isTypeAccess(); + } + if (currentType == receiverType || currentType.isSuperclassOf((ReferenceBinding) receiverType)){ + if (depth > 0) invocationSite.setDepth(depth); + return true; + } + } + depth++; + currentType = currentType.enclosingType(); + } while (currentType != null); + return false; + } + + if (isPrivate()) { + // answer true if the receiverType is the declaringClass + // AND the invocationType and the declaringClass have a common enclosingType + if (receiverType != declaringClass) return false; + + if (invocationType != declaringClass) { + ReferenceBinding outerInvocationType = invocationType; + ReferenceBinding temp = outerInvocationType.enclosingType(); + while (temp != null) { + outerInvocationType = temp; + temp = temp.enclosingType(); + } + + ReferenceBinding outerDeclaringClass = declaringClass; + temp = outerDeclaringClass.enclosingType(); + while (temp != null) { + outerDeclaringClass = temp; + temp = temp.enclosingType(); + } + if (outerInvocationType != outerDeclaringClass) return false; + } + return true; + } + + // isDefault() + if (invocationType.fPackage != declaringClass.fPackage) return false; + + // receiverType can be an array binding in one case... see if you can change it + if (receiverType instanceof ArrayBinding) + return false; + ReferenceBinding currentType = (ReferenceBinding) receiverType; + PackageBinding declaringPackage = declaringClass.fPackage; + do { + if (declaringClass == currentType) return true; + if (declaringPackage != currentType.fPackage) return false; + } while ((currentType = currentType.superclass()) != null); + return false; +} +public final int getAccessFlags() { + return modifiers & AccJustFlag; +} + +/* Answer true if the receiver has default visibility +*/ + +public final boolean isDefault() { + return !isPublic() && !isProtected() && !isPrivate(); +} +/* Answer true if the receiver is a deprecated field +*/ + +public final boolean isDeprecated() { + return (modifiers & AccDeprecated) != 0; +} +/* Answer true if the receiver has private visibility +*/ + +public final boolean isPrivate() { + return (modifiers & AccPrivate) != 0; +} +/* Answer true if the receiver has private visibility and is used locally +*/ + +public final boolean isPrivateUsed() { + return (modifiers & AccPrivateUsed) != 0; +} +/* Answer true if the receiver has protected visibility +*/ + +public final boolean isProtected() { + return (modifiers & AccProtected) != 0; +} +/* Answer true if the receiver has public visibility +*/ + +public final boolean isPublic() { + return (modifiers & AccPublic) != 0; +} +/* Answer true if the receiver is a static field +*/ + +public final boolean isStatic() { + return (modifiers & AccStatic) != 0; +} +/* Answer true if the receiver is not defined in the source of the declaringClass +*/ + +public final boolean isSynthetic() { + return (modifiers & AccSynthetic) != 0; +} +/* Answer true if the receiver is a transient field +*/ + +public final boolean isTransient() { + return (modifiers & AccTransient) != 0; +} +/* Answer true if the receiver's declaring type is deprecated (or any of its enclosing types) +*/ + +public final boolean isViewedAsDeprecated() { + return (modifiers & AccDeprecated) != 0 || + (modifiers & AccDeprecatedImplicitly) != 0; +} +/* Answer true if the receiver is a volatile field +*/ + +public final boolean isVolatile() { + return (modifiers & AccVolatile) != 0; +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/ImportBinding.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/ImportBinding.java new file mode 100644 index 0000000..6eb0985 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/ImportBinding.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.ast.ImportReference; + +public class ImportBinding extends Binding { + public char[][] compoundName; + public boolean onDemand; + public ImportReference reference; + + Binding resolvedImport; // must ensure the import is resolved + +public ImportBinding(char[][] compoundName, boolean isOnDemand, Binding binding, ImportReference reference) { + this.compoundName = compoundName; + this.onDemand = isOnDemand; + this.resolvedImport = binding; + this.reference = reference; +} +/* API +* Answer the receiver's binding type from Binding.BindingID. +*/ + +public final int bindingType() { + return IMPORT; +} +public char[] readableName() { + if (onDemand) + return CharOperation.concat(CharOperation.concatWith(compoundName, '.'), ".*".toCharArray()); //$NON-NLS-1$ + else + return CharOperation.concatWith(compoundName, '.'); +} +public String toString() { + return "import : " + new String(readableName()); //$NON-NLS-1$ +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/InnerEmulationDependency.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/InnerEmulationDependency.java new file mode 100644 index 0000000..e722789 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/InnerEmulationDependency.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +public class InnerEmulationDependency{ + + public BlockScope scope; + public boolean wasEnclosingInstanceSupplied; + + public InnerEmulationDependency(BlockScope scope, boolean wasEnclosingInstanceSupplied) { + this.scope = scope; + this.wasEnclosingInstanceSupplied = wasEnclosingInstanceSupplied; + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/InvocationSite.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/InvocationSite.java new file mode 100644 index 0000000..e9703ba --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/InvocationSite.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +public interface InvocationSite { + boolean isSuperAccess(); + boolean isTypeAccess(); + void setDepth(int depth); + void setFieldIndex(int depth); + + // in case the receiver type does not match the actual receiver type + // e.g. pkg.Type.C (receiver type of C is type of source context, + // but actual receiver type is pkg.Type) + // e.g2. in presence of implicit access to enclosing type + void setActualReceiverType(ReferenceBinding receiverType); + int sourceStart(); + int sourceEnd(); +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/LocalTypeBinding.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/LocalTypeBinding.java new file mode 100644 index 0000000..cacc605 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/LocalTypeBinding.java @@ -0,0 +1,149 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.ast.CaseStatement; +import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; +import org.eclipse.jdt.internal.compiler.util.Util; + +public final class LocalTypeBinding extends NestedTypeBinding { + final static char[] LocalTypePrefix = { '$', 'L', 'o', 'c', 'a', 'l', '$' }; + + private InnerEmulationDependency[] dependents; + public ArrayBinding[] localArrayBindings; // used to cache array bindings of various dimensions for this local type + public CaseStatement switchCase; // from 1.4 on, local types should not be accessed across switch case blocks (52221) + +public LocalTypeBinding(ClassScope scope, SourceTypeBinding enclosingType, CaseStatement switchCase) { + super( + new char[][] {CharOperation.concat(LocalTypePrefix, scope.referenceContext.name)}, + scope, + enclosingType); + + if (this.sourceName == TypeDeclaration.ANONYMOUS_EMPTY_NAME) + this.tagBits |= AnonymousTypeMask; + else + this.tagBits |= LocalTypeMask; + this.switchCase = switchCase; +} +/* Record a dependency onto a source target type which may be altered +* by the end of the innerclass emulation. Later on, we will revisit +* all its dependents so as to update them (see updateInnerEmulationDependents()). +*/ + +public void addInnerEmulationDependent(BlockScope dependentScope, boolean wasEnclosingInstanceSupplied) { + int index; + if (dependents == null) { + index = 0; + dependents = new InnerEmulationDependency[1]; + } else { + index = dependents.length; + for (int i = 0; i < index; i++) + if (dependents[i].scope == dependentScope) + return; // already stored + System.arraycopy(dependents, 0, (dependents = new InnerEmulationDependency[index + 1]), 0, index); + } + dependents[index] = new InnerEmulationDependency(dependentScope, wasEnclosingInstanceSupplied); + // System.out.println("Adding dependency: "+ new String(scope.enclosingType().readableName()) + " --> " + new String(this.readableName())); +} +/* Answer the receiver's constant pool name. +* +* NOTE: This method should only be used during/after code gen. +*/ + +public char[] constantPoolName() /* java/lang/Object */ { + return constantPoolName; +} + +ArrayBinding createArrayType(int dimensionCount) { + if (localArrayBindings == null) { + localArrayBindings = new ArrayBinding[] {new ArrayBinding(this, dimensionCount)}; + return localArrayBindings[0]; + } + + // find the cached array binding for this dimensionCount (if any) + int length = localArrayBindings.length; + for (int i = 0; i < length; i++) + if (localArrayBindings[i].dimensions == dimensionCount) + return localArrayBindings[i]; + + // no matching array + System.arraycopy(localArrayBindings, 0, localArrayBindings = new ArrayBinding[length + 1], 0, length); + return localArrayBindings[length] = new ArrayBinding(this, dimensionCount); +} + +public char[] readableName() { + if (isAnonymousType()) { + if (superInterfaces == NoSuperInterfaces) + return ("<"+Util.bind("binding.subclass",new String(superclass.readableName())) + ">").toCharArray(); //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-1$ + else + return ("<"+Util.bind("binding.implementation",new String(superInterfaces[0].readableName())) + ">").toCharArray(); //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-1$ + } else if (isMemberType()) { + return CharOperation.concat(enclosingType().readableName(), sourceName, '.'); + } else { + return sourceName; + } +} + +public char[] shortReadableName() { + if (isAnonymousType()) { + if (superInterfaces == NoSuperInterfaces) + return ("<"+Util.bind("binding.subclass",new String(superclass.shortReadableName())) + ">").toCharArray(); //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-1$ + else + return ("<"+Util.bind("binding.implementation",new String(superInterfaces[0].shortReadableName())) + ">").toCharArray(); //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-1$ + } else if (isMemberType()) { + return CharOperation.concat(enclosingType().shortReadableName(), sourceName, '.'); + } else { + return sourceName; + } +} + +// Record that the type is a local member type +public void setAsMemberType() { + tagBits |= MemberTypeMask; +} + +public void setConstantPoolName(char[] computedConstantPoolName) /* java/lang/Object */ { + this.constantPoolName = computedConstantPoolName; +} + +public char[] sourceName() { + if (isAnonymousType()) { + //return readableName(); + if (superInterfaces == NoSuperInterfaces) + return ("<"+Util.bind("binding.subclass",new String(superclass.sourceName())) + ">").toCharArray(); //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-1$ + else + return ("<"+Util.bind("binding.implementation",new String(superInterfaces[0].sourceName())) + ">").toCharArray(); //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-1$ + + } else + return sourceName; +} +public String toString() { + if (isAnonymousType()) + return "Anonymous type : " + super.toString(); //$NON-NLS-1$ + if (isMemberType()) + return "Local member type : " + new String(sourceName()) + " " + super.toString(); //$NON-NLS-2$ //$NON-NLS-1$ + return "Local type : " + new String(sourceName()) + " " + super.toString(); //$NON-NLS-2$ //$NON-NLS-1$ +} +/* Trigger the dependency mechanism forcing the innerclass emulation +* to be propagated to all dependent source types. +*/ + +public void updateInnerEmulationDependents() { + if (dependents != null) { + for (int i = 0; i < dependents.length; i++) { + InnerEmulationDependency dependency = dependents[i]; + // System.out.println("Updating " + new String(this.readableName()) + " --> " + new String(dependency.scope.enclosingType().readableName())); + dependency.scope.propagateInnerEmulation(this, dependency.wasEnclosingInstanceSupplied); + } + } +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/LocalVariableBinding.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/LocalVariableBinding.java new file mode 100644 index 0000000..0ab99f2 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/LocalVariableBinding.java @@ -0,0 +1,113 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; +import org.eclipse.jdt.internal.compiler.impl.Constant; + +public class LocalVariableBinding extends VariableBinding { + + public boolean isArgument; + public int resolvedPosition; // for code generation (position in method context) + + public static final int UNUSED = 0; + public static final int USED = 1; + public static final int FAKE_USED = 2; + public int useFlag; // for flow analysis (default is UNUSED) + + public BlockScope declaringScope; // back-pointer to its declaring scope + public LocalDeclaration declaration; // for source-positions + + public int[] initializationPCs; + public int initializationCount = 0; + + // for synthetic local variables + public LocalVariableBinding(char[] name, TypeBinding type, int modifiers, boolean isArgument) { + + this.name = name; + this.type = type; + this.modifiers = modifiers; + this.isArgument = isArgument; + if (isArgument) + this.constant = Constant.NotAConstant; + } + + // regular local variable or argument + public LocalVariableBinding(LocalDeclaration declaration, TypeBinding type, int modifiers, boolean isArgument) { + + this(declaration.name, type, modifiers, isArgument); + this.declaration = declaration; + } + + /* API + * Answer the receiver's binding type from Binding.BindingID. + */ + public final int bindingType() { + + return LOCAL; + } + + // Answer whether the variable binding is a secret variable added for code gen purposes + public boolean isSecret() { + + return declaration == null && !isArgument; + } + + public void recordInitializationEndPC(int pc) { + + if (initializationPCs[((initializationCount - 1) << 1) + 1] == -1) + initializationPCs[((initializationCount - 1) << 1) + 1] = pc; + } + + public void recordInitializationStartPC(int pc) { + + if (initializationPCs == null) return; + // optimize cases where reopening a contiguous interval + if ((initializationCount > 0) && (initializationPCs[ ((initializationCount - 1) << 1) + 1] == pc)) { + initializationPCs[ ((initializationCount - 1) << 1) + 1] = -1; // reuse previous interval (its range will be augmented) + } else { + int index = initializationCount << 1; + if (index == initializationPCs.length) { + System.arraycopy(initializationPCs, 0, (initializationPCs = new int[initializationCount << 2]), 0, index); + } + initializationPCs[index] = pc; + initializationPCs[index + 1] = -1; + initializationCount++; + } + } + + public String toString() { + + String s = super.toString(); + switch (useFlag){ + case USED: + s += "[pos: " + String.valueOf(resolvedPosition) + "]"; //$NON-NLS-2$ //$NON-NLS-1$ + break; + case UNUSED: + s += "[pos: unused]"; //$NON-NLS-1$ + break; + case FAKE_USED: + s += "[pos: fake_used]"; //$NON-NLS-1$ + break; + } + s += "[id:" + String.valueOf(id) + "]"; //$NON-NLS-2$ //$NON-NLS-1$ + if (initializationCount > 0) { + s += "[pc: "; //$NON-NLS-1$ + for (int i = 0; i < initializationCount; i++) { + if (i > 0) + s += ", "; //$NON-NLS-1$ + s += String.valueOf(initializationPCs[i << 1]) + "-" + ((initializationPCs[(i << 1) + 1] == -1) ? "?" : String.valueOf(initializationPCs[(i<< 1) + 1])); //$NON-NLS-2$ //$NON-NLS-1$ + } + s += "]"; //$NON-NLS-1$ + } + return s; + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java new file mode 100644 index 0000000..a7a9c9c --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java @@ -0,0 +1,590 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; +import org.eclipse.jdt.internal.compiler.env.IBinaryType; +import org.eclipse.jdt.internal.compiler.env.INameEnvironment; +import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer; +import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; +import org.eclipse.jdt.internal.compiler.impl.ITypeRequestor; +import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; +import org.eclipse.jdt.internal.compiler.util.HashtableOfPackage; +import org.eclipse.jdt.internal.compiler.util.Util; + +public class LookupEnvironment implements BaseTypes, ProblemReasons, TypeConstants { + public CompilerOptions options; + public ProblemReporter problemReporter; + public ITypeRequestor typeRequestor; + + PackageBinding defaultPackage; + ImportBinding[] defaultImports; + HashtableOfPackage knownPackages; + static final ProblemPackageBinding TheNotFoundPackage = new ProblemPackageBinding(CharOperation.NO_CHAR, NotFound); + static final ProblemReferenceBinding TheNotFoundType = new ProblemReferenceBinding(CharOperation.NO_CHAR, NotFound); + + private INameEnvironment nameEnvironment; + private MethodVerifier verifier; + private ArrayBinding[][] uniqueArrayBindings; + + private CompilationUnitDeclaration[] units = new CompilationUnitDeclaration[4]; + private int lastUnitIndex = -1; + private int lastCompletedUnitIndex = -1; + public CompilationUnitDeclaration unitBeingCompleted = null; // only set while completing units + + // indicate in which step on the compilation we are. + // step 1 : build the reference binding + // step 2 : conect the hierarchy (connect bindings) + // step 3 : build fields and method bindings. + private int stepCompleted; + final static int BUILD_TYPE_HIERARCHY = 1; + final static int CHECK_AND_SET_IMPORTS = 2; + final static int CONNECT_TYPE_HIERARCHY = 3; + final static int BUILD_FIELDS_AND_METHODS = 4; + + // shared byte[]'s used by ClassFile to avoid allocating MBs during a build + public boolean sharedArraysUsed = true; // set to false once actual arrays are allocated + public byte[] sharedClassFileHeader = null; + public byte[] sharedClassFileContents = null; + +public LookupEnvironment(ITypeRequestor typeRequestor, CompilerOptions options, ProblemReporter problemReporter, INameEnvironment nameEnvironment) { + this.typeRequestor = typeRequestor; + this.options = options; + this.problemReporter = problemReporter; + this.defaultPackage = new PackageBinding(this); // assume the default package always exists + this.defaultImports = null; + this.nameEnvironment = nameEnvironment; + this.knownPackages = new HashtableOfPackage(); + this.uniqueArrayBindings = new ArrayBinding[5][]; + this.uniqueArrayBindings[0] = new ArrayBinding[50]; // start off the most common 1 dimension array @ 50 +} +/* Ask the oracle for a type which corresponds to the compoundName. +* Answer null if the name cannot be found. +*/ + +public ReferenceBinding askForType(char[][] compoundName) { + NameEnvironmentAnswer answer = nameEnvironment.findType(compoundName); + if (answer == null) + return null; + + if (answer.isBinaryType()) + // the type was found as a .class file + typeRequestor.accept(answer.getBinaryType(), computePackageFrom(compoundName)); + else if (answer.isCompilationUnit()) + // the type was found as a .java file, try to build it then search the cache + typeRequestor.accept(answer.getCompilationUnit()); + else if (answer.isSourceType()) + // the type was found as a source model + typeRequestor.accept(answer.getSourceTypes(), computePackageFrom(compoundName)); + + return getCachedType(compoundName); +} +/* Ask the oracle for a type named name in the packageBinding. +* Answer null if the name cannot be found. +*/ + +ReferenceBinding askForType(PackageBinding packageBinding, char[] name) { + if (packageBinding == null) { + if (defaultPackage == null) + return null; + packageBinding = defaultPackage; + } + NameEnvironmentAnswer answer = nameEnvironment.findType(name, packageBinding.compoundName); + if (answer == null) + return null; + + if (answer.isBinaryType()) + // the type was found as a .class file + typeRequestor.accept(answer.getBinaryType(), packageBinding); + else if (answer.isCompilationUnit()) + // the type was found as a .java file, try to build it then search the cache + typeRequestor.accept(answer.getCompilationUnit()); + else if (answer.isSourceType()) + // the type was found as a source model + typeRequestor.accept(answer.getSourceTypes(), packageBinding); + + return packageBinding.getType0(name); +} +/* Create the initial type bindings for the compilation unit. +* +* See completeTypeBindings() for a description of the remaining steps +* +* NOTE: This method can be called multiple times as additional source files are needed +*/ + +public void buildTypeBindings(CompilationUnitDeclaration unit) { + CompilationUnitScope scope = new CompilationUnitScope(unit, this); + scope.buildTypeBindings(); + + int unitsLength = units.length; + if (++lastUnitIndex >= unitsLength) + System.arraycopy(units, 0, units = new CompilationUnitDeclaration[2 * unitsLength], 0, unitsLength); + units[lastUnitIndex] = unit; +} +/* Cache the binary type since we know it is needed during this compile. +* +* Answer the created BinaryTypeBinding or null if the type is already in the cache. +*/ + +public BinaryTypeBinding cacheBinaryType(IBinaryType binaryType) { + return cacheBinaryType(binaryType, true); +} +/* Cache the binary type since we know it is needed during this compile. +* +* Answer the created BinaryTypeBinding or null if the type is already in the cache. +*/ + +public BinaryTypeBinding cacheBinaryType(IBinaryType binaryType, boolean needFieldsAndMethods) { + char[][] compoundName = CharOperation.splitOn('/', binaryType.getName()); + ReferenceBinding existingType = getCachedType(compoundName); + + if (existingType == null || existingType instanceof UnresolvedReferenceBinding) + // only add the binary type if its not already in the cache + return createBinaryTypeFrom(binaryType, computePackageFrom(compoundName), needFieldsAndMethods); + return null; // the type already exists & can be retrieved from the cache +} +/* +* 1. Connect the type hierarchy for the type bindings created for parsedUnits. +* 2. Create the field bindings +* 3. Create the method bindings +*/ + +/* We know each known compilationUnit is free of errors at this point... +* +* Each step will create additional bindings unless a problem is detected, in which +* case either the faulty import/superinterface/field/method will be skipped or a +* suitable replacement will be substituted (such as Object for a missing superclass) +*/ + +public void completeTypeBindings() { + stepCompleted = BUILD_TYPE_HIERARCHY; + + for (int i = this.lastCompletedUnitIndex + 1; i <= this.lastUnitIndex; i++) { + (this.unitBeingCompleted = this.units[i]).scope.checkAndSetImports(); + } + stepCompleted = CHECK_AND_SET_IMPORTS; + + for (int i = this.lastCompletedUnitIndex + 1; i <= this.lastUnitIndex; i++) { + (this.unitBeingCompleted = this.units[i]).scope.connectTypeHierarchy(); + } + stepCompleted = CONNECT_TYPE_HIERARCHY; + + for (int i = this.lastCompletedUnitIndex + 1; i <= this.lastUnitIndex; i++) { + (this.unitBeingCompleted = this.units[i]).scope.buildFieldsAndMethods(); + this.units[i] = null; // release unnecessary reference to the parsed unit + } + stepCompleted = BUILD_FIELDS_AND_METHODS; + this.lastCompletedUnitIndex = this.lastUnitIndex; + this.unitBeingCompleted = null; +} +/* +* 1. Connect the type hierarchy for the type bindings created for parsedUnits. +* 2. Create the field bindings +* 3. Create the method bindings +*/ + +/* +* Each step will create additional bindings unless a problem is detected, in which +* case either the faulty import/superinterface/field/method will be skipped or a +* suitable replacement will be substituted (such as Object for a missing superclass) +*/ + +public void completeTypeBindings(CompilationUnitDeclaration parsedUnit) { + if (stepCompleted == BUILD_FIELDS_AND_METHODS) { + // This can only happen because the original set of units are completely built and + // are now being processed, so we want to treat all the additional units as a group + // until they too are completely processed. + completeTypeBindings(); + } else { + if (parsedUnit.scope == null) return; // parsing errors were too severe + + if (stepCompleted >= CHECK_AND_SET_IMPORTS) + (this.unitBeingCompleted = parsedUnit).scope.checkAndSetImports(); + + if (stepCompleted >= CONNECT_TYPE_HIERARCHY) + (this.unitBeingCompleted = parsedUnit).scope.connectTypeHierarchy(); + + this.unitBeingCompleted = null; + } +} +/* +* Used by other compiler tools which do not start by calling completeTypeBindings(). +* +* 1. Connect the type hierarchy for the type bindings created for parsedUnits. +* 2. Create the field bindings +* 3. Create the method bindings +*/ + +public void completeTypeBindings(CompilationUnitDeclaration parsedUnit, boolean buildFieldsAndMethods) { + if (parsedUnit.scope == null) return; // parsing errors were too severe + + (this.unitBeingCompleted = parsedUnit).scope.checkAndSetImports(); + parsedUnit.scope.connectTypeHierarchy(); + if (buildFieldsAndMethods) + parsedUnit.scope.buildFieldsAndMethods(); + this.unitBeingCompleted = null; +} +private PackageBinding computePackageFrom(char[][] constantPoolName) { + if (constantPoolName.length == 1) + return defaultPackage; + + PackageBinding packageBinding = getPackage0(constantPoolName[0]); + if (packageBinding == null || packageBinding == TheNotFoundPackage) { + packageBinding = new PackageBinding(constantPoolName[0], this); + knownPackages.put(constantPoolName[0], packageBinding); + } + + for (int i = 1, length = constantPoolName.length - 1; i < length; i++) { + PackageBinding parent = packageBinding; + if ((packageBinding = parent.getPackage0(constantPoolName[i])) == null || packageBinding == TheNotFoundPackage) { + packageBinding = new PackageBinding(CharOperation.subarray(constantPoolName, 0, i + 1), parent, this); + parent.addPackage(packageBinding); + } + } + return packageBinding; +} +/* Used to guarantee array type identity. +*/ + +ArrayBinding createArrayType(TypeBinding type, int dimensionCount) { + if (type instanceof LocalTypeBinding) // cache local type arrays with the local type itself + return ((LocalTypeBinding) type).createArrayType(dimensionCount); + + // find the array binding cache for this dimension + int dimIndex = dimensionCount - 1; + int length = uniqueArrayBindings.length; + ArrayBinding[] arrayBindings; + if (dimIndex < length) { + if ((arrayBindings = uniqueArrayBindings[dimIndex]) == null) + uniqueArrayBindings[dimIndex] = arrayBindings = new ArrayBinding[10]; + } else { + System.arraycopy( + uniqueArrayBindings, 0, + uniqueArrayBindings = new ArrayBinding[dimensionCount][], 0, + length); + uniqueArrayBindings[dimIndex] = arrayBindings = new ArrayBinding[10]; + } + + // find the cached array binding for this leaf component type (if any) + int index = -1; + length = arrayBindings.length; + while (++index < length) { + ArrayBinding currentBinding = arrayBindings[index]; + if (currentBinding == null) // no matching array, but space left + return arrayBindings[index] = new ArrayBinding(type, dimensionCount); + if (currentBinding.leafComponentType == type) + return currentBinding; + } + + // no matching array, no space left + System.arraycopy( + arrayBindings, 0, + (arrayBindings = new ArrayBinding[length * 2]), 0, + length); + uniqueArrayBindings[dimIndex] = arrayBindings; + return arrayBindings[length] = new ArrayBinding(type, dimensionCount); +} +public BinaryTypeBinding createBinaryTypeFrom(IBinaryType binaryType, PackageBinding packageBinding) { + return createBinaryTypeFrom(binaryType, packageBinding, true); +} +public BinaryTypeBinding createBinaryTypeFrom(IBinaryType binaryType, PackageBinding packageBinding, boolean needFieldsAndMethods) { + BinaryTypeBinding binaryBinding = new BinaryTypeBinding(packageBinding, binaryType, this); + + // resolve any array bindings which reference the unresolvedType + ReferenceBinding cachedType = packageBinding.getType0(binaryBinding.compoundName[binaryBinding.compoundName.length - 1]); + if (cachedType != null) { + if (cachedType.isBinaryBinding()) // sanity check before the cast... at this point the cache should ONLY contain unresolved types + return (BinaryTypeBinding) cachedType; + + UnresolvedReferenceBinding unresolvedType = (UnresolvedReferenceBinding) cachedType; + unresolvedType.resolvedType = binaryBinding; + updateArrayCache(unresolvedType, binaryBinding); + } + + packageBinding.addType(binaryBinding); + binaryBinding.cachePartsFrom(binaryType, needFieldsAndMethods); + return binaryBinding; +} +/* Used to create packages from the package statement. +*/ + +PackageBinding createPackage(char[][] compoundName) { + PackageBinding packageBinding = getPackage0(compoundName[0]); + if (packageBinding == null || packageBinding == TheNotFoundPackage) { + packageBinding = new PackageBinding(compoundName[0], this); + knownPackages.put(compoundName[0], packageBinding); + } + + for (int i = 1, length = compoundName.length; i < length; i++) { + // check to see if it collides with a known type... + // this case can only happen if the package does not exist as a directory in the file system + // otherwise when the source type was defined, the correct error would have been reported + // unless its an unresolved type which is referenced from an inconsistent class file + ReferenceBinding type = packageBinding.getType0(compoundName[i]); + if (type != null && type != TheNotFoundType && !(type instanceof UnresolvedReferenceBinding)) + return null; + + PackageBinding parent = packageBinding; + if ((packageBinding = parent.getPackage0(compoundName[i])) == null || packageBinding == TheNotFoundPackage) { + // if the package is unknown, check to see if a type exists which would collide with the new package + // catches the case of a package statement of: package java.lang.Object; + // since the package can be added after a set of source files have already been compiled, we need + // whenever a package statement is encountered + if (nameEnvironment.findType(compoundName[i], parent.compoundName) != null) + return null; + + packageBinding = new PackageBinding(CharOperation.subarray(compoundName, 0, i + 1), parent, this); + parent.addPackage(packageBinding); + } + } + return packageBinding; +} +/* Answer the type for the compoundName if it exists in the cache. +* Answer theNotFoundType if it could not be resolved the first time +* it was looked up, otherwise answer null. +* +* NOTE: Do not use for nested types... the answer is NOT the same for a.b.C or a.b.C.D.E +* assuming C is a type in both cases. In the a.b.C.D.E case, null is the answer. +*/ + +public ReferenceBinding getCachedType(char[][] compoundName) { + if (compoundName.length == 1) { + if (defaultPackage == null) + return null; + return defaultPackage.getType0(compoundName[0]); + } + + PackageBinding packageBinding = getPackage0(compoundName[0]); + if (packageBinding == null || packageBinding == TheNotFoundPackage) + return null; + + for (int i = 1, packageLength = compoundName.length - 1; i < packageLength; i++) + if ((packageBinding = packageBinding.getPackage0(compoundName[i])) == null || packageBinding == TheNotFoundPackage) + return null; + return packageBinding.getType0(compoundName[compoundName.length - 1]); +} +/* Answer the top level package named name if it exists in the cache. +* Answer theNotFoundPackage if it could not be resolved the first time +* it was looked up, otherwise answer null. +* +* NOTE: Senders must convert theNotFoundPackage into a real problem +* package if its to returned. +*/ + +PackageBinding getPackage0(char[] name) { + return knownPackages.get(name); +} +/* Answer the top level package named name. +* Ask the oracle for the package if its not in the cache. +* Answer null if the package cannot be found. +*/ + +PackageBinding getTopLevelPackage(char[] name) { + PackageBinding packageBinding = getPackage0(name); + if (packageBinding != null) { + if (packageBinding == TheNotFoundPackage) + return null; + return packageBinding; + } + + if (nameEnvironment.isPackage(null, name)) { + knownPackages.put(name, packageBinding = new PackageBinding(name, this)); + return packageBinding; + } + + knownPackages.put(name, TheNotFoundPackage); // saves asking the oracle next time + return null; +} +/* Answer the type corresponding to the compoundName. +* Ask the oracle for the type if its not in the cache. +* Answer null if the type cannot be found... likely a fatal error. +*/ + +public ReferenceBinding getType(char[][] compoundName) { + ReferenceBinding referenceBinding; + + if (compoundName.length == 1) { + if (defaultPackage == null) + return null; + + if ((referenceBinding = defaultPackage.getType0(compoundName[0])) == null) { + PackageBinding packageBinding = getPackage0(compoundName[0]); + if (packageBinding != null && packageBinding != TheNotFoundPackage) + return null; // collides with a known package... should not call this method in such a case + referenceBinding = askForType(defaultPackage, compoundName[0]); + } + } else { + PackageBinding packageBinding = getPackage0(compoundName[0]); + if (packageBinding == TheNotFoundPackage) + return null; + + if (packageBinding != null) { + for (int i = 1, packageLength = compoundName.length - 1; i < packageLength; i++) { + if ((packageBinding = packageBinding.getPackage0(compoundName[i])) == null) + break; + if (packageBinding == TheNotFoundPackage) + return null; + } + } + + if (packageBinding == null) + referenceBinding = askForType(compoundName); + else if ((referenceBinding = packageBinding.getType0(compoundName[compoundName.length - 1])) == null) + referenceBinding = askForType(packageBinding, compoundName[compoundName.length - 1]); + } + + if (referenceBinding == null || referenceBinding == TheNotFoundType) + return null; + if (referenceBinding instanceof UnresolvedReferenceBinding) + referenceBinding = ((UnresolvedReferenceBinding) referenceBinding).resolve(this); + + // compoundName refers to a nested type incorrectly (for example, package1.A$B) + if (referenceBinding.isNestedType()) + return new ProblemReferenceBinding(compoundName, InternalNameProvided); + return referenceBinding; +} +/* Answer the type corresponding to the name from the binary file. +* Does not ask the oracle for the type if its not found in the cache... instead an +* unresolved type is returned which must be resolved before used. +* +* NOTE: Does NOT answer base types nor array types! +* +* NOTE: Aborts compilation if the class file cannot be found. +*/ + +ReferenceBinding getTypeFromConstantPoolName(char[] signature, int start, int end) { + if (end == -1) + end = signature.length; + + char[][] compoundName = CharOperation.splitOn('/', signature, start, end); + ReferenceBinding binding = getCachedType(compoundName); + if (binding == null) { + PackageBinding packageBinding = computePackageFrom(compoundName); + binding = new UnresolvedReferenceBinding(compoundName, packageBinding); + packageBinding.addType(binding); + } else if (binding == TheNotFoundType) { + problemReporter.isClassPathCorrect(compoundName, null); + return null; // will not get here since the above error aborts the compilation + } + return binding; +} +/* Answer the type corresponding to the signature from the binary file. +* Does not ask the oracle for the type if its not found in the cache... instead an +* unresolved type is returned which must be resolved before used. +* +* NOTE: Does answer base types & array types. +* +* NOTE: Aborts compilation if the class file cannot be found. +*/ + +TypeBinding getTypeFromSignature(char[] signature, int start, int end) { + int dimension = 0; + while (signature[start] == '[') { + start++; + dimension++; + } + if (end == -1) + end = signature.length - 1; + + // Just switch on signature[start] - the L case is the else + TypeBinding binding = null; + if (start == end) { + switch (signature[start]) { + case 'I' : + binding = IntBinding; + break; + case 'Z' : + binding = BooleanBinding; + break; + case 'V' : + binding = VoidBinding; + break; + case 'C' : + binding = CharBinding; + break; + case 'D' : + binding = DoubleBinding; + break; + case 'B' : + binding = ByteBinding; + break; + case 'F' : + binding = FloatBinding; + break; + case 'J' : + binding = LongBinding; + break; + case 'S' : + binding = ShortBinding; + break; + default : + throw new Error(Util.bind("error.undefinedBaseType",String.valueOf(signature[start]))); //$NON-NLS-1$ + } + } else { + binding = getTypeFromConstantPoolName(signature, start + 1, end); + } + + if (dimension == 0) + return binding; + return createArrayType(binding, dimension); +} +/* Ask the oracle if a package exists named name in the package named compoundName. +*/ + +boolean isPackage(char[][] compoundName, char[] name) { + if (compoundName == null || compoundName.length == 0) + return nameEnvironment.isPackage(null, name); + return nameEnvironment.isPackage(compoundName, name); +} +// The method verifier is lazily initialized to guarantee the receiver, the compiler & the oracle are ready. + +public MethodVerifier methodVerifier() { + if (verifier == null) + verifier = new MethodVerifier(this); + return verifier; +} +public void reset() { + this.defaultPackage = new PackageBinding(this); // assume the default package always exists + this.defaultImports = null; + this.knownPackages = new HashtableOfPackage(); + + this.verifier = null; + for (int i = this.uniqueArrayBindings.length; --i >= 0;) + this.uniqueArrayBindings[i] = null; + this.uniqueArrayBindings[0] = new ArrayBinding[50]; // start off the most common 1 dimension array @ 50 + + for (int i = this.units.length; --i >= 0;) + this.units[i] = null; + this.lastUnitIndex = -1; + this.lastCompletedUnitIndex = -1; + this.unitBeingCompleted = null; // in case AbortException occurred + + // name environment has a longer life cycle, and must be reset in + // the code which created it. +} +void updateArrayCache(UnresolvedReferenceBinding unresolvedType, ReferenceBinding resolvedType) { + nextDimension : for (int i = 0, length = uniqueArrayBindings.length; i < length; i++) { + ArrayBinding[] arrayBindings = uniqueArrayBindings[i]; + if (arrayBindings != null) { + for (int j = 0, max = arrayBindings.length; j < max; j++) { + ArrayBinding currentBinding = arrayBindings[j]; + if (currentBinding == null) + continue nextDimension; + if (currentBinding.leafComponentType == unresolvedType) { + currentBinding.leafComponentType = resolvedType; + continue nextDimension; + } + } + } + } +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/MemberTypeBinding.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/MemberTypeBinding.java new file mode 100644 index 0000000..dc24ea2 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/MemberTypeBinding.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +import org.eclipse.jdt.core.compiler.CharOperation; + +public final class MemberTypeBinding extends NestedTypeBinding { +public MemberTypeBinding(char[][] compoundName, ClassScope scope, SourceTypeBinding enclosingType) { + super(compoundName, scope, enclosingType); + this.tagBits |= MemberTypeMask; +} +void checkSyntheticArgsAndFields() { + if (this.isStatic()) return; + if (this.isInterface()) return; + this.addSyntheticArgumentAndField(this.enclosingType); +} +/* Answer the receiver's constant pool name. +* +* NOTE: This method should only be used during/after code gen. +*/ + +public char[] constantPoolName() /* java/lang/Object */ { + if (constantPoolName != null) + return constantPoolName; + + return constantPoolName = CharOperation.concat(enclosingType().constantPoolName(), sourceName, '$'); +} +public String toString() { + return "Member type : " + new String(sourceName()) + " " + super.toString(); //$NON-NLS-2$ //$NON-NLS-1$ +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java new file mode 100644 index 0000000..0441fb3 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java @@ -0,0 +1,538 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration; + +public class MethodBinding extends Binding implements BaseTypes, TypeConstants { + public int modifiers; + public char[] selector; + public TypeBinding returnType; + public TypeBinding[] parameters; + public ReferenceBinding[] thrownExceptions; + public ReferenceBinding declaringClass; + + char[] signature; + +protected MethodBinding() { + // for creating problem or synthetic method +} +public MethodBinding(int modifiers, char[] selector, TypeBinding returnType, TypeBinding[] args, ReferenceBinding[] exceptions, ReferenceBinding declaringClass) { + this.modifiers = modifiers; + this.selector = selector; + this.returnType = returnType; + this.parameters = (args == null || args.length == 0) ? NoParameters : args; + this.thrownExceptions = (exceptions == null || exceptions.length == 0) ? NoExceptions : exceptions; + this.declaringClass = declaringClass; + + // propagate the strictfp & deprecated modifiers + if (this.declaringClass != null) { + if (this.declaringClass.isStrictfp()) + if (!(isNative() || isAbstract())) + this.modifiers |= AccStrictfp; + if (this.declaringClass.isViewedAsDeprecated() && !isDeprecated()) + this.modifiers |= AccDeprecatedImplicitly; + } +} +public MethodBinding(int modifiers, TypeBinding[] args, ReferenceBinding[] exceptions, ReferenceBinding declaringClass) { + this(modifiers, ConstructorDeclaration.ConstantPoolName, VoidBinding, args, exceptions, declaringClass); +} +// special API used to change method declaring class for runtime visibility check +public MethodBinding(MethodBinding initialMethodBinding, ReferenceBinding declaringClass) { + this.modifiers = initialMethodBinding.modifiers; + this.selector = initialMethodBinding.selector; + this.returnType = initialMethodBinding.returnType; + this.parameters = initialMethodBinding.parameters; + this.thrownExceptions = initialMethodBinding.thrownExceptions; + this.declaringClass = declaringClass; +} +/* Answer true if the argument types & the receiver's parameters are equal +*/ + +public final boolean areParametersEqual(MethodBinding method) { + TypeBinding[] args = method.parameters; + if (parameters == args) + return true; + + int length = parameters.length; + if (length != args.length) + return false; + + for (int i = 0; i < length; i++) + if (parameters[i] != args[i]) + return false; + return true; +} +/* API +* Answer the receiver's binding type from Binding.BindingID. +*/ + +public final int bindingType() { + return METHOD; +} +/* Answer true if the receiver is visible to the type provided by the scope. +* InvocationSite implements isSuperAccess() to provide additional information +* if the receiver is protected. +* +* NOTE: This method should ONLY be sent if the receiver is a constructor. +* +* NOTE: Cannot invoke this method with a compilation unit scope. +*/ + +public final boolean canBeSeenBy(InvocationSite invocationSite, Scope scope) { + if (isPublic()) return true; + + SourceTypeBinding invocationType = scope.enclosingSourceType(); + if (invocationType == declaringClass) return true; + + if (isProtected()) { + // answer true if the receiver is in the same package as the invocationType + if (invocationType.fPackage == declaringClass.fPackage) return true; + return invocationSite.isSuperAccess(); + } + + if (isPrivate()) { + // answer true if the invocationType and the declaringClass have a common enclosingType + // already know they are not the identical type + ReferenceBinding outerInvocationType = invocationType; + ReferenceBinding temp = outerInvocationType.enclosingType(); + while (temp != null) { + outerInvocationType = temp; + temp = temp.enclosingType(); + } + + ReferenceBinding outerDeclaringClass = declaringClass; + temp = outerDeclaringClass.enclosingType(); + while (temp != null) { + outerDeclaringClass = temp; + temp = temp.enclosingType(); + } + return outerInvocationType == outerDeclaringClass; + } + + // isDefault() + return invocationType.fPackage == declaringClass.fPackage; +} +/* Answer true if the receiver is visible to the type provided by the scope. +* InvocationSite implements isSuperAccess() to provide additional information +* if the receiver is protected. +* +* NOTE: Cannot invoke this method with a compilation unit scope. +*/ +public final boolean canBeSeenBy(TypeBinding receiverType, InvocationSite invocationSite, Scope scope) { + if (isPublic()) return true; + + SourceTypeBinding invocationType = scope.enclosingSourceType(); + if (invocationType == declaringClass && invocationType == receiverType) return true; + + if (isProtected()) { + // answer true if the invocationType is the declaringClass or they are in the same package + // OR the invocationType is a subclass of the declaringClass + // AND the receiverType is the invocationType or its subclass + // OR the method is a static method accessed directly through a type + // OR previous assertions are true for one of the enclosing type + if (invocationType == declaringClass) return true; + if (invocationType.fPackage == declaringClass.fPackage) return true; + + ReferenceBinding currentType = invocationType; + int depth = 0; + do { + if (declaringClass.isSuperclassOf(currentType)) { + if (invocationSite.isSuperAccess()){ + return true; + } + // receiverType can be an array binding in one case... see if you can change it + if (receiverType instanceof ArrayBinding){ + return false; + } + if (isStatic()){ + if (depth > 0) invocationSite.setDepth(depth); + return true; // see 1FMEPDL - return invocationSite.isTypeAccess(); + } + if (currentType == receiverType || currentType.isSuperclassOf((ReferenceBinding) receiverType)){ + if (depth > 0) invocationSite.setDepth(depth); + return true; + } + } + depth++; + currentType = currentType.enclosingType(); + } while (currentType != null); + return false; + } + + if (isPrivate()) { + // answer true if the receiverType is the declaringClass + // AND the invocationType and the declaringClass have a common enclosingType + if (receiverType != declaringClass) return false; + + if (invocationType != declaringClass) { + ReferenceBinding outerInvocationType = invocationType; + ReferenceBinding temp = outerInvocationType.enclosingType(); + while (temp != null) { + outerInvocationType = temp; + temp = temp.enclosingType(); + } + + ReferenceBinding outerDeclaringClass = declaringClass; + temp = outerDeclaringClass.enclosingType(); + while (temp != null) { + outerDeclaringClass = temp; + temp = temp.enclosingType(); + } + if (outerInvocationType != outerDeclaringClass) return false; + } + return true; + } + + // isDefault() + if (invocationType.fPackage != declaringClass.fPackage) return false; + + // receiverType can be an array binding in one case... see if you can change it + if (receiverType instanceof ArrayBinding) + return false; + ReferenceBinding type = (ReferenceBinding) receiverType; + PackageBinding declaringPackage = declaringClass.fPackage; + do { + if (declaringClass == type) return true; + if (declaringPackage != type.fPackage) return false; + } while ((type = type.superclass()) != null); + return false; +} +/* + * Answer the declaring class to use in the constant pool + * may not be a reference binding (see subtypes) + */ +public TypeBinding constantPoolDeclaringClass() { + return this.declaringClass; +} +/* Answer the receiver's constant pool name. +* +* for constructors +* for clinit methods +* or the source name of the method +*/ +public final char[] constantPoolName() { + return selector; +} +public final int getAccessFlags() { + return modifiers & AccJustFlag; +} + +/* Answer true if the receiver is an abstract method +*/ +public final boolean isAbstract() { + return (modifiers & AccAbstract) != 0; +} + +/* Answer true if the receiver is a bridge method +*/ +public final boolean isBridge() { + return (modifiers & AccBridge) != 0; +} + +/* Answer true if the receiver is a constructor +*/ +public final boolean isConstructor() { + return selector == ConstructorDeclaration.ConstantPoolName; +} +protected boolean isConstructorRelated() { + return isConstructor(); +} + +/* Answer true if the receiver has default visibility +*/ +public final boolean isDefault() { + return !isPublic() && !isProtected() && !isPrivate(); +} + +/* Answer true if the receiver is a system generated default abstract method +*/ +public final boolean isDefaultAbstract() { + return (modifiers & AccDefaultAbstract) != 0; +} + +/* Answer true if the receiver is a deprecated method +*/ +public final boolean isDeprecated() { + return (modifiers & AccDeprecated) != 0; +} + +/* Answer true if the receiver is final and cannot be overridden +*/ +public final boolean isFinal() { + return (modifiers & AccFinal) != 0; +} + +/* Answer true if the receiver is implementing another method + * in other words, it is overriding and concrete, and overriden method is abstract + * Only set for source methods +*/ +public final boolean isImplementing() { + return (modifiers & AccImplementing) != 0; +} + +/* Answer true if the receiver is a native method +*/ +public final boolean isNative() { + return (modifiers & AccNative) != 0; +} + +/* Answer true if the receiver is overriding another method + * Only set for source methods +*/ +public final boolean isOverriding() { + return (modifiers & AccOverriding) != 0; +} +/* + * Answer true if the receiver is a "public static void main(String[])" method + */ +public final boolean isMain() { + if (this.selector.length == 4 && CharOperation.equals(this.selector, MAIN) + && ((this.modifiers & (AccPublic | AccStatic)) != 0) + && VoidBinding == this.returnType + && this.parameters.length == 1) { + TypeBinding paramType = this.parameters[0]; + if (paramType.dimensions() == 1 && paramType.leafComponentType().id == TypeIds.T_JavaLangString) { + return true; + } + } + return false; +} +/* Answer true if the receiver has private visibility +*/ +public final boolean isPrivate() { + return (modifiers & AccPrivate) != 0; +} + +/* Answer true if the receiver has private visibility and is used locally +*/ +public final boolean isPrivateUsed() { + return (modifiers & AccPrivateUsed) != 0; +} + +/* Answer true if the receiver has protected visibility +*/ +public final boolean isProtected() { + return (modifiers & AccProtected) != 0; +} + +/* Answer true if the receiver has public visibility +*/ +public final boolean isPublic() { + return (modifiers & AccPublic) != 0; +} + +/* Answer true if the receiver got requested to clear the private modifier + * during private access emulation. + */ +public final boolean isRequiredToClearPrivateModifier() { + return (modifiers & AccClearPrivateModifier) != 0; +} + +/* Answer true if the receiver is a static method +*/ +public final boolean isStatic() { + return (modifiers & AccStatic) != 0; +} + +/* Answer true if all float operations must adher to IEEE 754 float/double rules +*/ +public final boolean isStrictfp() { + return (modifiers & AccStrictfp) != 0; +} + +/* Answer true if the receiver is a synchronized method +*/ +public final boolean isSynchronized() { + return (modifiers & AccSynchronized) != 0; +} + +/* Answer true if the receiver has public visibility +*/ +public final boolean isSynthetic() { + return (modifiers & AccSynthetic) != 0; +} + +/* Answer true if the receiver is a vararg method +*/ +public final boolean isVararg() { + return (modifiers & AccVarargs) != 0; +} + +/* Answer true if the receiver's declaring type is deprecated (or any of its enclosing types) +*/ +public final boolean isViewedAsDeprecated() { + return (modifiers & AccDeprecated) != 0 || + (modifiers & AccDeprecatedImplicitly) != 0; +} + +public char[] readableName() /* foo(int, Thread) */ { + StringBuffer buffer = new StringBuffer(parameters.length + 1 * 20); + if (isConstructor()) + buffer.append(declaringClass.sourceName()); + else + buffer.append(selector); + buffer.append('('); + if (parameters != NoParameters) { + for (int i = 0, length = parameters.length; i < length; i++) { + if (i > 0) + buffer.append(", "); //$NON-NLS-1$ + buffer.append(parameters[i].sourceName()); + } + } + buffer.append(')'); + return buffer.toString().toCharArray(); +} + +/** + * @see org.eclipse.jdt.internal.compiler.lookup.Binding#shortReadableName() + */ +public char[] shortReadableName() { + StringBuffer buffer = new StringBuffer(parameters.length + 1 * 20); + if (isConstructor()) + buffer.append(declaringClass.shortReadableName()); + else + buffer.append(selector); + buffer.append('('); + if (parameters != NoParameters) { + for (int i = 0, length = parameters.length; i < length; i++) { + if (i > 0) + buffer.append(", "); //$NON-NLS-1$ + buffer.append(parameters[i].shortReadableName()); + } + } + buffer.append(')'); + return buffer.toString().toCharArray(); +} + +protected final void setSelector(char[] selector) { + this.selector = selector; + this.signature = null; +} + +/* Answer the receiver's signature. +* +* NOTE: This method should only be used during/after code gen. +* The signature is cached so if the signature of the return type or any parameter +* type changes, the cached state is invalid. +*/ +public final char[] signature() /* (ILjava/lang/Thread;)Ljava/lang/Object; */ { + if (signature != null) + return signature; + + StringBuffer buffer = new StringBuffer(parameters.length + 1 * 20); + buffer.append('('); + + TypeBinding[] targetParameters = this.parameters; + boolean considerSynthetics = isConstructorRelated() && declaringClass.isNestedType(); + if (considerSynthetics) { + + // take into account the synthetic argument type signatures as well + ReferenceBinding[] syntheticArgumentTypes = declaringClass.syntheticEnclosingInstanceTypes(); + int count = syntheticArgumentTypes == null ? 0 : syntheticArgumentTypes.length; + for (int i = 0; i < count; i++) { + buffer.append(syntheticArgumentTypes[i].signature()); + } + + if (this instanceof SyntheticAccessMethodBinding) { + targetParameters = ((SyntheticAccessMethodBinding)this).targetMethod.parameters; + } + } + + if (targetParameters != NoParameters) { + for (int i = 0; i < targetParameters.length; i++) { + buffer.append(targetParameters[i].signature()); + } + } + if (considerSynthetics) { + SyntheticArgumentBinding[] syntheticOuterArguments = declaringClass.syntheticOuterLocalVariables(); + int count = syntheticOuterArguments == null ? 0 : syntheticOuterArguments.length; + for (int i = 0; i < count; i++) { + buffer.append(syntheticOuterArguments[i].type.signature()); + } + // move the extra padding arguments of the synthetic constructor invocation to the end + for (int i = targetParameters.length, extraLength = parameters.length; i < extraLength; i++) { + buffer.append(parameters[i].signature()); + } + } + buffer.append(')'); + buffer.append(returnType.signature()); + return signature = buffer.toString().toCharArray(); +} +public final int sourceEnd() { + AbstractMethodDeclaration method = sourceMethod(); + if (method == null) + return 0; + return method.sourceEnd; +} +AbstractMethodDeclaration sourceMethod() { + SourceTypeBinding sourceType; + try { + sourceType = (SourceTypeBinding) declaringClass; + } catch (ClassCastException e) { + return null; + } + + AbstractMethodDeclaration[] methods = sourceType.scope.referenceContext.methods; + for (int i = methods.length; --i >= 0;) + if (this == methods[i].binding) + return methods[i]; + return null; +} +public final int sourceStart() { + AbstractMethodDeclaration method = sourceMethod(); + if (method == null) + return 0; + return method.sourceStart; +} +/* During private access emulation, the binding can be requested to loose its + * private visibility when the class file is dumped. + */ + +public final void tagForClearingPrivateModifier() { + modifiers |= AccClearPrivateModifier; +} +public String toString() { + String s = (returnType != null) ? returnType.debugName() : "NULL TYPE"; //$NON-NLS-1$ + s += " "; //$NON-NLS-1$ + s += (selector != null) ? new String(selector) : "UNNAMED METHOD"; //$NON-NLS-1$ + + s += "("; //$NON-NLS-1$ + if (parameters != null) { + if (parameters != NoParameters) { + for (int i = 0, length = parameters.length; i < length; i++) { + if (i > 0) + s += ", "; //$NON-NLS-1$ + s += (parameters[i] != null) ? parameters[i].debugName() : "NULL TYPE"; //$NON-NLS-1$ + } + } + } else { + s += "NULL PARAMETERS"; //$NON-NLS-1$ + } + s += ") "; //$NON-NLS-1$ + + if (thrownExceptions != null) { + if (thrownExceptions != NoExceptions) { + s += "throws "; //$NON-NLS-1$ + for (int i = 0, length = thrownExceptions.length; i < length; i++) { + if (i > 0) + s += ", "; //$NON-NLS-1$ + s += (thrownExceptions[i] != null) ? thrownExceptions[i].debugName() : "NULL TYPE"; //$NON-NLS-1$ + } + } + } else { + s += "NULL THROWN EXCEPTIONS"; //$NON-NLS-1$ + } + return s; +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java new file mode 100644 index 0000000..92b806b --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java @@ -0,0 +1,492 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +import org.eclipse.jdt.internal.compiler.ast.*; +import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration; +import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference; +import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; +import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; +import org.eclipse.jdt.internal.compiler.codegen.CodeStream; +import org.eclipse.jdt.internal.compiler.flow.FlowInfo; +import org.eclipse.jdt.internal.compiler.flow.UnconditionalFlowInfo; +import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; +import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; +import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; + +/** + * Particular block scope used for methods, constructors or clinits, representing + * its outermost blockscope. Note also that such a scope will be provided to enclose + * field initializers subscopes as well. + */ +public class MethodScope extends BlockScope { + + public ReferenceContext referenceContext; + public boolean isStatic; // method modifier or initializer one + + //fields used during name resolution + public boolean isConstructorCall = false; + public FieldBinding initializedField; // the field being initialized + public int lastVisibleFieldID = -1; // the ID of the last field which got declared + // note that #initializedField can be null AND lastVisibleFieldID >= 0, when processing instance field initializers. + + // flow analysis + public int analysisIndex; // for setting flow-analysis id + public boolean isPropagatingInnerClassEmulation; + + // for local variables table attributes + public int lastIndex = 0; + public long[] definiteInits = new long[4]; + public long[][] extraDefiniteInits = new long[4][]; + + // inner-emulation + public SyntheticArgumentBinding[] extraSyntheticArguments; + + public MethodScope(ClassScope parent, ReferenceContext context, boolean isStatic) { + + super(METHOD_SCOPE, parent); + locals = new LocalVariableBinding[5]; + this.referenceContext = context; + this.isStatic = isStatic; + this.startIndex = 0; + } + + /* Spec : 8.4.3 & 9.4 + */ + private void checkAndSetModifiersForConstructor(MethodBinding methodBinding) { + + int modifiers = methodBinding.modifiers; + if ((modifiers & AccAlternateModifierProblem) != 0) + problemReporter().duplicateModifierForMethod( + methodBinding.declaringClass, + (AbstractMethodDeclaration) referenceContext); + + if (((ConstructorDeclaration) referenceContext).isDefaultConstructor) { + if (methodBinding.declaringClass.isPublic()) + modifiers |= AccPublic; + else if (methodBinding.declaringClass.isProtected()) + modifiers |= AccProtected; + } + + // after this point, tests on the 16 bits reserved. + int realModifiers = modifiers & AccJustFlag; + + // check for abnormal modifiers + int unexpectedModifiers = + ~(AccPublic | AccPrivate | AccProtected | AccStrictfp); + if ((realModifiers & unexpectedModifiers) != 0) + problemReporter().illegalModifierForMethod( + methodBinding.declaringClass, + (AbstractMethodDeclaration) referenceContext); + else if ( + (((AbstractMethodDeclaration) referenceContext).modifiers & AccStrictfp) != 0) + // must check the parse node explicitly + problemReporter().illegalModifierForMethod( + methodBinding.declaringClass, + (AbstractMethodDeclaration) referenceContext); + + // check for incompatible modifiers in the visibility bits, isolate the visibility bits + int accessorBits = realModifiers & (AccPublic | AccProtected | AccPrivate); + if ((accessorBits & (accessorBits - 1)) != 0) { + problemReporter().illegalVisibilityModifierCombinationForMethod( + methodBinding.declaringClass, + (AbstractMethodDeclaration) referenceContext); + + // need to keep the less restrictive + if ((accessorBits & AccPublic) != 0) { + if ((accessorBits & AccProtected) != 0) + modifiers ^= AccProtected; + if ((accessorBits & AccPrivate) != 0) + modifiers ^= AccPrivate; + } + if ((accessorBits & AccProtected) != 0) + if ((accessorBits & AccPrivate) != 0) + modifiers ^= AccPrivate; + } + + // if the receiver's declaring class is a private nested type, then make sure the receiver is not private (causes problems for inner type emulation) + if (methodBinding.declaringClass.isPrivate()) + if ((modifiers & AccPrivate) != 0) + modifiers ^= AccPrivate; + + methodBinding.modifiers = modifiers; + } + + /* Spec : 8.4.3 & 9.4 + */ + private void checkAndSetModifiersForMethod(MethodBinding methodBinding) { + + int modifiers = methodBinding.modifiers; + if ((modifiers & AccAlternateModifierProblem) != 0) + problemReporter().duplicateModifierForMethod( + methodBinding.declaringClass, + (AbstractMethodDeclaration) referenceContext); + + // after this point, tests on the 16 bits reserved. + int realModifiers = modifiers & AccJustFlag; + + // set the requested modifiers for a method in an interface + if (methodBinding.declaringClass.isInterface()) { + if ((realModifiers & ~(AccPublic | AccAbstract)) != 0) + problemReporter().illegalModifierForInterfaceMethod( + methodBinding.declaringClass, + (AbstractMethodDeclaration) referenceContext); + return; + } + + // check for abnormal modifiers + int unexpectedModifiers = + ~( + AccPublic + | AccPrivate + | AccProtected + | AccAbstract + | AccStatic + | AccFinal + | AccSynchronized + | AccNative + | AccStrictfp); + if ((realModifiers & unexpectedModifiers) != 0) + problemReporter().illegalModifierForMethod( + methodBinding.declaringClass, + (AbstractMethodDeclaration) referenceContext); + + // check for incompatible modifiers in the visibility bits, isolate the visibility bits + int accessorBits = realModifiers & (AccPublic | AccProtected | AccPrivate); + if ((accessorBits & (accessorBits - 1)) != 0) { + problemReporter().illegalVisibilityModifierCombinationForMethod( + methodBinding.declaringClass, + (AbstractMethodDeclaration) referenceContext); + + // need to keep the less restrictive + if ((accessorBits & AccPublic) != 0) { + if ((accessorBits & AccProtected) != 0) + modifiers ^= AccProtected; + if ((accessorBits & AccPrivate) != 0) + modifiers ^= AccPrivate; + } + if ((accessorBits & AccProtected) != 0) + if ((accessorBits & AccPrivate) != 0) + modifiers ^= AccPrivate; + } + + // check for modifiers incompatible with abstract modifier + if ((modifiers & AccAbstract) != 0) { + int incompatibleWithAbstract = + AccPrivate | AccStatic | AccFinal | AccSynchronized | AccNative | AccStrictfp; + if ((modifiers & incompatibleWithAbstract) != 0) + problemReporter().illegalAbstractModifierCombinationForMethod( + methodBinding.declaringClass, + (AbstractMethodDeclaration) referenceContext); + if (!methodBinding.declaringClass.isAbstract()) + problemReporter().abstractMethodInAbstractClass( + (SourceTypeBinding) methodBinding.declaringClass, + (AbstractMethodDeclaration) referenceContext); + } + + /* DISABLED for backward compatibility with javac (if enabled should also mark private methods as final) + // methods from a final class are final : 8.4.3.3 + if (methodBinding.declaringClass.isFinal()) + modifiers |= AccFinal; + */ + // native methods cannot also be tagged as strictfp + if ((modifiers & AccNative) != 0 && (modifiers & AccStrictfp) != 0) + problemReporter().nativeMethodsCannotBeStrictfp( + methodBinding.declaringClass, + (AbstractMethodDeclaration) referenceContext); + + // static members are only authorized in a static member or top level type + if (((realModifiers & AccStatic) != 0) + && methodBinding.declaringClass.isNestedType() + && !methodBinding.declaringClass.isStatic()) + problemReporter().unexpectedStaticModifierForMethod( + methodBinding.declaringClass, + (AbstractMethodDeclaration) referenceContext); + + methodBinding.modifiers = modifiers; + } + + /* Compute variable positions in scopes given an initial position offset + * ignoring unused local variables. + * + * Deal with arguments here, locals and subscopes are processed in BlockScope method + */ + public void computeLocalVariablePositions(int initOffset, CodeStream codeStream) { + + boolean isReportingUnusedArgument = false; + + if (referenceContext instanceof AbstractMethodDeclaration) { + AbstractMethodDeclaration methodDecl = (AbstractMethodDeclaration)referenceContext; + MethodBinding method = methodDecl.binding; + CompilerOptions options = compilationUnitScope().environment.options; + if (!(method.isAbstract() + || (method.isImplementing() && !options.reportUnusedParameterWhenImplementingAbstract) + || (method.isOverriding() && !method.isImplementing() && !options.reportUnusedParameterWhenOverridingConcrete) + || method.isMain())) { + isReportingUnusedArgument = true; + } + } + this.offset = initOffset; + this.maxOffset = initOffset; + + // manage arguments + int ilocal = 0, maxLocals = this.localIndex; + while (ilocal < maxLocals) { + LocalVariableBinding local = locals[ilocal]; + if (local == null || !local.isArgument) break; // done with arguments + + // do not report fake used variable + if (isReportingUnusedArgument + && local.useFlag == LocalVariableBinding.UNUSED + && ((local.declaration.bits & ASTNode.IsLocalDeclarationReachableMASK) != 0)) { // declaration is reachable + this.problemReporter().unusedArgument(local.declaration); + } + + // record user-defined argument for attribute generation + codeStream.record(local); + + // assign variable position + local.resolvedPosition = this.offset; + + if ((local.type == LongBinding) || (local.type == DoubleBinding)) { + this.offset += 2; + } else { + this.offset++; + } + // check for too many arguments/local variables + if (this.offset > 0xFF) { // no more than 255 words of arguments + this.problemReporter().noMoreAvailableSpaceForArgument(local, local.declaration); + } + ilocal++; + } + + // sneak in extra argument before other local variables + if (extraSyntheticArguments != null) { + for (int iarg = 0, maxArguments = extraSyntheticArguments.length; iarg < maxArguments; iarg++){ + SyntheticArgumentBinding argument = extraSyntheticArguments[iarg]; + argument.resolvedPosition = this.offset; + if ((argument.type == LongBinding) || (argument.type == DoubleBinding)){ + this.offset += 2; + } else { + this.offset++; + } + if (this.offset > 0xFF) { // no more than 255 words of arguments + this.problemReporter().noMoreAvailableSpaceForArgument(argument, (ASTNode)this.referenceContext); + } + } + } + this.computeLocalVariablePositions(ilocal, this.offset, codeStream); + } + + /* Error management: + * keep null for all the errors that prevent the method to be created + * otherwise return a correct method binding (but without the element + * that caused the problem) : ie : Incorrect thrown exception + */ + MethodBinding createMethod(AbstractMethodDeclaration method) { + + // is necessary to ensure error reporting + this.referenceContext = method; + method.scope = this; + SourceTypeBinding declaringClass = referenceType().binding; + int modifiers = method.modifiers | AccUnresolved; + if (method.isConstructor()) { + if (method.isDefaultConstructor()) { + modifiers |= AccIsDefaultConstructor; + } + method.binding = new MethodBinding(modifiers, null, null, declaringClass); + checkAndSetModifiersForConstructor(method.binding); + } else { + if (declaringClass.isInterface()) + modifiers |= AccPublic | AccAbstract; + method.binding = + new MethodBinding(modifiers, method.selector, null, null, null, declaringClass); + checkAndSetModifiersForMethod(method.binding); + } + this.isStatic = method.binding.isStatic(); + return method.binding; + } + + /* Overridden to detect the error case inside an explicit constructor call: + + class X { + int i; + X myX; + X(X x) { + this(i, myX.i, x.i); // same for super calls... only the first 2 field accesses are errors + } + } + */ + public FieldBinding findField( + TypeBinding receiverType, + char[] fieldName, + InvocationSite invocationSite, + boolean needResolve) { + + FieldBinding field = super.findField(receiverType, fieldName, invocationSite, needResolve); + if (field == null) + return null; + if (!field.isValidBinding()) + return field; // answer the error field + if (field.isStatic()) + return field; // static fields are always accessible + + if (!isConstructorCall || receiverType != enclosingSourceType()) + return field; + + if (invocationSite instanceof SingleNameReference) + return new ProblemFieldBinding( + field, // closest match + field.declaringClass, + fieldName, + NonStaticReferenceInConstructorInvocation); + if (invocationSite instanceof QualifiedNameReference) { + // look to see if the field is the first binding + QualifiedNameReference name = (QualifiedNameReference) invocationSite; + if (name.binding == null) + // only true when the field is the fieldbinding at the beginning of name's tokens + return new ProblemFieldBinding( + field, // closest match + field.declaringClass, + fieldName, + NonStaticReferenceInConstructorInvocation); + } + return field; + } + + public boolean isInsideConstructor() { + + return (referenceContext instanceof ConstructorDeclaration); + } + + public boolean isInsideInitializer() { + + return (referenceContext instanceof TypeDeclaration); + } + + public boolean isInsideInitializerOrConstructor() { + + return (referenceContext instanceof TypeDeclaration) + || (referenceContext instanceof ConstructorDeclaration); + } + + /* Answer the problem reporter to use for raising new problems. + * + * Note that as a side-effect, this updates the current reference context + * (unit, type or method) in case the problem handler decides it is necessary + * to abort. + */ + public ProblemReporter problemReporter() { + + MethodScope outerMethodScope; + if ((outerMethodScope = outerMostMethodScope()) == this) { + ProblemReporter problemReporter = referenceCompilationUnit().problemReporter; + problemReporter.referenceContext = referenceContext; + return problemReporter; + } + return outerMethodScope.problemReporter(); + } + + public final int recordInitializationStates(FlowInfo flowInfo) { + + if (!flowInfo.isReachable()) return -1; + + UnconditionalFlowInfo unconditionalFlowInfo = flowInfo.unconditionalInits(); + long[] extraInits = unconditionalFlowInfo.extraDefiniteInits; + long inits = unconditionalFlowInfo.definiteInits; + checkNextEntry : for (int i = lastIndex; --i >= 0;) { + if (definiteInits[i] == inits) { + long[] otherInits = extraDefiniteInits[i]; + if ((extraInits != null) && (otherInits != null)) { + if (extraInits.length == otherInits.length) { + int j, max; + for (j = 0, max = extraInits.length; j < max; j++) { + if (extraInits[j] != otherInits[j]) { + continue checkNextEntry; + } + } + return i; + } + } else { + if ((extraInits == null) && (otherInits == null)) { + return i; + } + } + } + } + + // add a new entry + if (definiteInits.length == lastIndex) { + // need a resize + System.arraycopy( + definiteInits, + 0, + (definiteInits = new long[lastIndex + 20]), + 0, + lastIndex); + System.arraycopy( + extraDefiniteInits, + 0, + (extraDefiniteInits = new long[lastIndex + 20][]), + 0, + lastIndex); + } + definiteInits[lastIndex] = inits; + if (extraInits != null) { + extraDefiniteInits[lastIndex] = new long[extraInits.length]; + System.arraycopy( + extraInits, + 0, + extraDefiniteInits[lastIndex], + 0, + extraInits.length); + } + return lastIndex++; + } + + /* Answer the reference method of this scope, or null if initialization scoope. + */ + public AbstractMethodDeclaration referenceMethod() { + + if (referenceContext instanceof AbstractMethodDeclaration) return (AbstractMethodDeclaration) referenceContext; + return null; + } + + /* Answer the reference type of this scope. + * + * It is the nearest enclosing type of this scope. + */ + public TypeDeclaration referenceType() { + + return ((ClassScope) parent).referenceContext; + } + + String basicToString(int tab) { + + String newLine = "\n"; //$NON-NLS-1$ + for (int i = tab; --i >= 0;) + newLine += "\t"; //$NON-NLS-1$ + + String s = newLine + "--- Method Scope ---"; //$NON-NLS-1$ + newLine += "\t"; //$NON-NLS-1$ + s += newLine + "locals:"; //$NON-NLS-1$ + for (int i = 0; i < localIndex; i++) + s += newLine + "\t" + locals[i].toString(); //$NON-NLS-1$ + s += newLine + "startIndex = " + startIndex; //$NON-NLS-1$ + s += newLine + "isConstructorCall = " + isConstructorCall; //$NON-NLS-1$ + s += newLine + "initializedField = " + initializedField; //$NON-NLS-1$ + s += newLine + "lastVisibleFieldID = " + lastVisibleFieldID; //$NON-NLS-1$ + s += newLine + "referenceContext = " + referenceContext; //$NON-NLS-1$ + return s; + } + +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier.java new file mode 100644 index 0000000..115864c --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier.java @@ -0,0 +1,533 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; +import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; +import org.eclipse.jdt.internal.compiler.util.HashtableOfObject; + +public final class MethodVerifier implements TagBits, TypeConstants { + SourceTypeBinding type; + HashtableOfObject inheritedMethods; + HashtableOfObject currentMethods; + ReferenceBinding runtimeException; + ReferenceBinding errorException; + LookupEnvironment environment; +/* +Binding creation is responsible for reporting all problems with types: + - all modifier problems (duplicates & multiple visibility modifiers + incompatible combinations - abstract/final) + - plus invalid modifiers given the context (the verifier did not do this before) + - qualified name collisions between a type and a package (types in default packages are excluded) + - all type hierarchy problems: + - cycles in the superclass or superinterface hierarchy + - an ambiguous, invisible or missing superclass or superinterface + - extending a final class + - extending an interface instead of a class + - implementing a class instead of an interface + - implementing the same interface more than once (ie. duplicate interfaces) + - with nested types: + - shadowing an enclosing type's source name + - defining a static class or interface inside a non-static nested class + - defining an interface as a local type (local types can only be classes) +*/ +public MethodVerifier(LookupEnvironment environment) { + this.type = null; // Initialized with the public method verify(SourceTypeBinding) + this.inheritedMethods = null; + this.currentMethods = null; + this.runtimeException = null; + this.errorException = null; + this.environment = environment; +} +private boolean areParametersEqual(MethodBinding one, MethodBinding two) { + TypeBinding[] oneArgs = one.parameters; + TypeBinding[] twoArgs = two.parameters; + if (oneArgs == twoArgs) return true; + + int length = oneArgs.length; + if (length != twoArgs.length) return false; + + for (int i = 0; i < length; i++) + if (!areTypesEqual(oneArgs[i], twoArgs[i])) return false; + return true; +} +private boolean areReturnTypesEqual(MethodBinding one, MethodBinding two) { + return areTypesEqual(one.returnType, two.returnType); +} +private boolean areTypesEqual(TypeBinding one, TypeBinding two) { + if (one == two) return true; + if (one instanceof ReferenceBinding && two instanceof ReferenceBinding) + // can compare unresolved to resolved reference bindings + return CharOperation.equals(((ReferenceBinding) one).compoundName, ((ReferenceBinding) two).compoundName); + return false; // all other type bindings are identical +} +private void checkAbstractMethod(MethodBinding abstractMethod) { + if (mustImplementAbstractMethod(abstractMethod)) { + TypeDeclaration typeDeclaration = this.type.scope.referenceContext; + if (typeDeclaration != null) { + MethodDeclaration missingAbstractMethod = typeDeclaration.addMissingAbstractMethodFor(abstractMethod); + missingAbstractMethod.scope.problemReporter().abstractMethodMustBeImplemented(this.type, abstractMethod); + } else { + this.problemReporter().abstractMethodMustBeImplemented(this.type, abstractMethod); + } + } +} +private void checkAgainstInheritedMethods(MethodBinding currentMethod, MethodBinding[] methods, int length) { + nextMethod : for (int i = length; --i >= 0;) { + MethodBinding inheritedMethod = methods[i]; + if (currentMethod.isStatic() != inheritedMethod.isStatic()) { // Cannot override a static method or hide an instance method + this.problemReporter(currentMethod).staticAndInstanceConflict(currentMethod, inheritedMethod); + continue nextMethod; + } + + if (!currentMethod.isAbstract() && inheritedMethod.isAbstract()) { + if ((currentMethod.modifiers & CompilerModifiers.AccOverriding) == 0) + currentMethod.modifiers |= CompilerModifiers.AccImplementing; + } else { + currentMethod.modifiers |= CompilerModifiers.AccOverriding; + } + + if (!areReturnTypesEqual(currentMethod, inheritedMethod)) { + this.problemReporter(currentMethod).incompatibleReturnType(currentMethod, inheritedMethod); + } else { + if (currentMethod.thrownExceptions != NoExceptions) + this.checkExceptions(currentMethod, inheritedMethod); + if (inheritedMethod.isFinal()) + this.problemReporter(currentMethod).finalMethodCannotBeOverridden(currentMethod, inheritedMethod); + if (!this.isAsVisible(currentMethod, inheritedMethod)) + this.problemReporter(currentMethod).visibilityConflict(currentMethod, inheritedMethod); + if (environment.options.reportDeprecationWhenOverridingDeprecatedMethod && inheritedMethod.isViewedAsDeprecated()) { + if (!currentMethod.isViewedAsDeprecated() || environment.options.reportDeprecationInsideDeprecatedCode) { + // check against the other inherited methods to see if they hide this inheritedMethod + ReferenceBinding declaringClass = inheritedMethod.declaringClass; + if (declaringClass.isInterface()) + for (int j = length; --j >= 0;) + if (i != j && methods[j].declaringClass.implementsInterface(declaringClass, false)) + continue nextMethod; + + this.problemReporter(currentMethod).overridesDeprecatedMethod(currentMethod, inheritedMethod); + } + } + } + } +} +/* +"8.4.4" +Verify that newExceptions are all included in inheritedExceptions. +Assumes all exceptions are valid and throwable. +Unchecked exceptions (compatible with runtime & error) are ignored (see the spec on pg. 203). +*/ +private void checkExceptions(MethodBinding newMethod, MethodBinding inheritedMethod) { + ReferenceBinding[] newExceptions = resolvedExceptionTypesFor(newMethod); + ReferenceBinding[] inheritedExceptions = resolvedExceptionTypesFor(inheritedMethod); + for (int i = newExceptions.length; --i >= 0;) { + ReferenceBinding newException = newExceptions[i]; + int j = inheritedExceptions.length; + while (--j > -1 && !this.isSameClassOrSubclassOf(newException, inheritedExceptions[j])){/*empty*/} + if (j == -1) + if (!(newException.isCompatibleWith(this.runtimeException()) || newException.isCompatibleWith(this.errorException()))) + this.problemReporter(newMethod).incompatibleExceptionInThrowsClause(this.type, newMethod, inheritedMethod, newException); + } +} +private void checkInheritedMethods(MethodBinding[] methods, int length) { + MethodBinding first = methods[0]; + int index = length; + while (--index > 0 && areReturnTypesEqual(first, methods[index])){/*empty*/} + if (index > 0) { // All inherited methods do NOT have the same vmSignature + this.problemReporter().inheritedMethodsHaveIncompatibleReturnTypes(this.type, methods, length); + return; + } + + MethodBinding concreteMethod = null; + if (!type.isInterface()) { // ignore concrete methods for interfaces + for (int i = length; --i >= 0;) { // Remember that only one of the methods can be non-abstract + if (!methods[i].isAbstract()) { + concreteMethod = methods[i]; + break; + } + } + } + if (concreteMethod == null) { + if (this.type.isClass() && !this.type.isAbstract()) { + for (int i = length; --i >= 0;) { + if (mustImplementAbstractMethod(methods[i])) { + TypeDeclaration typeDeclaration = this.type.scope.referenceContext; + if (typeDeclaration != null) { + MethodDeclaration missingAbstractMethod = typeDeclaration.addMissingAbstractMethodFor(methods[0]); + missingAbstractMethod.scope.problemReporter().abstractMethodMustBeImplemented(this.type, methods[0]); + } else { + this.problemReporter().abstractMethodMustBeImplemented(this.type, methods[0]); + } + return; + } + } + } + return; + } + + MethodBinding[] abstractMethods = new MethodBinding[length - 1]; + index = 0; + for (int i = length; --i >= 0;) + if (methods[i] != concreteMethod) + abstractMethods[index++] = methods[i]; + + // Remember that interfaces can only define public instance methods + if (concreteMethod.isStatic()) + // Cannot inherit a static method which is specified as an instance method by an interface + this.problemReporter().staticInheritedMethodConflicts(type, concreteMethod, abstractMethods); + if (!concreteMethod.isPublic()) + // Cannot reduce visibility of a public method specified by an interface + this.problemReporter().inheritedMethodReducesVisibility(type, concreteMethod, abstractMethods); + if (concreteMethod.thrownExceptions != NoExceptions) + for (int i = abstractMethods.length; --i >= 0;) + this.checkExceptions(concreteMethod, abstractMethods[i]); +} +/* +For each inherited method identifier (message pattern - vm signature minus the return type) + if current method exists + if current's vm signature does not match an inherited signature then complain + else compare current's exceptions & visibility against each inherited method + else + if inherited methods = 1 + if inherited is abstract && type is NOT an interface or abstract, complain + else + if vm signatures do not match complain + else + find the concrete implementation amongst the abstract methods (can only be 1) + if one exists then + it must be a public instance method + compare concrete's exceptions against each abstract method + else + complain about missing implementation only if type is NOT an interface or abstract +*/ +private void checkMethods() { + boolean mustImplementAbstractMethods = this.type.isClass() && !this.type.isAbstract(); + boolean skipInheritedMethods = mustImplementAbstractMethods && this.type.superInterfaces() == NoSuperInterfaces + && this.type.superclass() != null && !this.type.superclass().isAbstract(); // have a single concrete superclass so only check overridden methods + char[][] methodSelectors = this.inheritedMethods.keyTable; + nextSelector : for (int s = methodSelectors.length; --s >= 0;) { + if (methodSelectors[s] == null) continue nextSelector; + + MethodBinding[] current = (MethodBinding[]) this.currentMethods.get(methodSelectors[s]); + if (current == null && skipInheritedMethods) + continue nextSelector; + + MethodBinding[] inherited = (MethodBinding[]) this.inheritedMethods.valueTable[s]; + if (inherited.length == 1 && current == null) { // handle the common case + if (mustImplementAbstractMethods && inherited[0].isAbstract()) + checkAbstractMethod(inherited[0]); + continue nextSelector; + } + + int index = -1; + MethodBinding[] matchingInherited = new MethodBinding[inherited.length]; + if (current != null) { + for (int i = 0, length1 = current.length; i < length1; i++) { + while (index >= 0) matchingInherited[index--] = null; // clear the previous contents of the matching methods + MethodBinding currentMethod = current[i]; + for (int j = 0, length2 = inherited.length; j < length2; j++) { + MethodBinding inheritedMethod = inherited[j]; + if (inheritedMethod != null && areParametersEqual(currentMethod, inheritedMethod)) { + matchingInherited[++index] = inheritedMethod; + inherited[j] = null; // do not want to find it again + } + } + if (index >= 0) + this.checkAgainstInheritedMethods(currentMethod, matchingInherited, index + 1); // pass in the length of matching + } + } + + for (int i = 0, length = inherited.length; i < length; i++) { + while (index >= 0) matchingInherited[index--] = null; // clear the previous contents of the matching methods + MethodBinding inheritedMethod = inherited[i]; + if (inheritedMethod != null) { + matchingInherited[++index] = inheritedMethod; + for (int j = i + 1; j < length; j++) { + if (inherited[j] != null && areParametersEqual(inheritedMethod, inherited[j])) { + matchingInherited[++index] = inherited[j]; + inherited[j] = null; // do not want to find it again + } + } + } + if (index > 0) + this.checkInheritedMethods(matchingInherited, index + 1); // pass in the length of matching + else if (mustImplementAbstractMethods && index == 0 && matchingInherited[0].isAbstract()) + checkAbstractMethod(matchingInherited[0]); + } + } +} +private void checkPackagePrivateAbstractMethod(MethodBinding abstractMethod) { + ReferenceBinding superType = this.type.superclass(); + char[] selector = abstractMethod.selector; + do { + if (!superType.isValidBinding()) return; + if (!superType.isAbstract()) return; // closer non abstract super type will be flagged instead + + MethodBinding[] methods = superType.getMethods(selector); + nextMethod : for (int m = methods.length; --m >= 0;) { + MethodBinding method = methods[m]; + if (!areReturnTypesEqual(method, abstractMethod) || !areParametersEqual(method, abstractMethod)) + continue nextMethod; + if (method.isPrivate() || method.isConstructor() || method.isDefaultAbstract()) + continue nextMethod; + if (superType.fPackage == abstractMethod.declaringClass.fPackage) return; // found concrete implementation of abstract method in same package + } + } while ((superType = superType.superclass()) != abstractMethod.declaringClass); + + // non visible abstract methods cannot be overridden so the type must be defined abstract + this.problemReporter().abstractMethodCannotBeOverridden(this.type, abstractMethod); +} +/* +Binding creation is responsible for reporting: + - all modifier problems (duplicates & multiple visibility modifiers + incompatible combinations) + - plus invalid modifiers given the context... examples: + - interface methods can only be public + - abstract methods can only be defined by abstract classes + - collisions... 2 methods with identical vmSelectors + - multiple methods with the same message pattern but different return types + - ambiguous, invisible or missing return/argument/exception types + - check the type of any array is not void + - check that each exception type is Throwable or a subclass of it +*/ +private void computeInheritedMethods() { + this.inheritedMethods = new HashtableOfObject(51); // maps method selectors to an array of methods... must search to match paramaters & return type + ReferenceBinding[][] interfacesToVisit = new ReferenceBinding[3][]; + int lastPosition = -1; + ReferenceBinding[] itsInterfaces = type.superInterfaces(); + if (itsInterfaces != NoSuperInterfaces) + interfacesToVisit[++lastPosition] = itsInterfaces; + + ReferenceBinding superType = this.type.isClass() + ? this.type.superclass() + : this.type.scope.getJavaLangObject(); // check interface methods against Object + HashtableOfObject nonVisibleDefaultMethods = new HashtableOfObject(3); // maps method selectors to an array of methods + boolean allSuperclassesAreAbstract = true; + + while (superType != null) { + if (superType.isValidBinding()) { + if (allSuperclassesAreAbstract) { + if (superType.isAbstract()) { + // only need to include superinterfaces if immediate superclasses are abstract + if ((itsInterfaces = superType.superInterfaces()) != NoSuperInterfaces) { + if (++lastPosition == interfacesToVisit.length) + System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition); + interfacesToVisit[lastPosition] = itsInterfaces; + } + } else { + allSuperclassesAreAbstract = false; + } + } + + MethodBinding[] methods = superType.unResolvedMethods(); + nextMethod : for (int m = methods.length; --m >= 0;) { + MethodBinding method = methods[m]; + if (method.isPrivate() || method.isConstructor() || method.isDefaultAbstract()) + continue nextMethod; + MethodBinding[] existingMethods = (MethodBinding[]) this.inheritedMethods.get(method.selector); + if (existingMethods != null) { + for (int i = 0, length = existingMethods.length; i < length; i++) { + if (areReturnTypesEqual(method, existingMethods[i]) && areParametersEqual(method, existingMethods[i])) { + if (method.isDefault() && method.isAbstract() && method.declaringClass.fPackage != type.fPackage) + checkPackagePrivateAbstractMethod(method); + continue nextMethod; + } + } + } + MethodBinding[] nonVisible = (MethodBinding[]) nonVisibleDefaultMethods.get(method.selector); + if (nonVisible != null) + for (int i = 0, l = nonVisible.length; i < l; i++) + if (areReturnTypesEqual(method, nonVisible[i]) && areParametersEqual(method, nonVisible[i])) + continue nextMethod; + + if (!method.isDefault() || method.declaringClass.fPackage == type.fPackage) { + if (existingMethods == null) { + existingMethods = new MethodBinding[] {method}; + } else { + int length = existingMethods.length; + System.arraycopy(existingMethods, 0, existingMethods = new MethodBinding[length + 1], 0, length); + existingMethods[length] = method; + } + this.inheritedMethods.put(method.selector, existingMethods); + } else { + if (nonVisible == null) { + nonVisible = new MethodBinding[] {method}; + } else { + int length = nonVisible.length; + System.arraycopy(nonVisible, 0, nonVisible = new MethodBinding[length + 1], 0, length); + nonVisible[length] = method; + } + nonVisibleDefaultMethods.put(method.selector, nonVisible); + + if (method.isAbstract() && !this.type.isAbstract()) // non visible abstract methods cannot be overridden so the type must be defined abstract + this.problemReporter().abstractMethodCannotBeOverridden(this.type, method); + + MethodBinding[] current = (MethodBinding[]) this.currentMethods.get(method.selector); + if (current != null) { // non visible methods cannot be overridden so a warning is issued + foundMatch : for (int i = 0, length = current.length; i < length; i++) { + if (areReturnTypesEqual(method, current[i]) && areParametersEqual(method, current[i])) { + this.problemReporter().overridesPackageDefaultMethod(current[i], method); + break foundMatch; + } + } + } + } + } + superType = superType.superclass(); + } + } + + for (int i = 0; i <= lastPosition; i++) { + ReferenceBinding[] interfaces = interfacesToVisit[i]; + for (int j = 0, l = interfaces.length; j < l; j++) { + superType = interfaces[j]; + if ((superType.tagBits & InterfaceVisited) == 0) { + superType.tagBits |= InterfaceVisited; + if (superType.isValidBinding()) { + if ((itsInterfaces = superType.superInterfaces()) != NoSuperInterfaces) { + if (++lastPosition == interfacesToVisit.length) + System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition); + interfacesToVisit[lastPosition] = itsInterfaces; + } + + MethodBinding[] methods = superType.unResolvedMethods(); + nextMethod : for (int m = methods.length; --m >= 0;) { // Interface methods are all abstract public + MethodBinding method = methods[m]; + MethodBinding[] existingMethods = (MethodBinding[]) this.inheritedMethods.get(method.selector); + if (existingMethods == null) { + existingMethods = new MethodBinding[] {method}; + } else { + int length = existingMethods.length; + for (int e = 0; e < length; e++) { + MethodBinding existing = existingMethods[e]; + if (areParametersEqual(method, existing) && existing.declaringClass.implementsInterface(superType, true)) + continue nextMethod; // skip interface method with the same signature if visible to its declaringClass + } + System.arraycopy(existingMethods, 0, existingMethods = new MethodBinding[length + 1], 0, length); + existingMethods[length] = method; + } + this.inheritedMethods.put(method.selector, existingMethods); + } + } + } + } + } + + // bit reinitialization + for (int i = 0; i <= lastPosition; i++) { + ReferenceBinding[] interfaces = interfacesToVisit[i]; + for (int j = 0, length = interfaces.length; j < length; j++) + interfaces[j].tagBits &= ~InterfaceVisited; + } +} +private void computeMethods() { + MethodBinding[] methods = type.methods(); + int size = methods.length; + this.currentMethods = new HashtableOfObject(size == 0 ? 1 : size); // maps method selectors to an array of methods... must search to match paramaters & return type + for (int m = size; --m >= 0;) { + MethodBinding method = methods[m]; + if (!(method.isConstructor() || method.isDefaultAbstract())) { // keep all methods which are NOT constructors or default abstract + MethodBinding[] existingMethods = (MethodBinding[]) this.currentMethods.get(method.selector); + if (existingMethods == null) + existingMethods = new MethodBinding[1]; + else + System.arraycopy(existingMethods, 0, + (existingMethods = new MethodBinding[existingMethods.length + 1]), 0, existingMethods.length - 1); + existingMethods[existingMethods.length - 1] = method; + this.currentMethods.put(method.selector, existingMethods); + } + } +} +private ReferenceBinding errorException() { + if (errorException == null) + this.errorException = this.type.scope.getJavaLangError(); + return errorException; +} +private boolean isAsVisible(MethodBinding newMethod, MethodBinding inheritedMethod) { + if (inheritedMethod.modifiers == newMethod.modifiers) return true; + + if (newMethod.isPublic()) return true; // Covers everything + if (inheritedMethod.isPublic()) return false; + + if (newMethod.isProtected()) return true; + if (inheritedMethod.isProtected()) return false; + + return !newMethod.isPrivate(); // The inheritedMethod cannot be private since it would not be visible +} +private boolean isSameClassOrSubclassOf(ReferenceBinding testClass, ReferenceBinding superclass) { + do { + if (testClass == superclass) return true; + } while ((testClass = testClass.superclass()) != null); + return false; +} +private boolean mustImplementAbstractMethod(MethodBinding abstractMethod) { + // if the type's superclass is an abstract class, then all abstract methods must be implemented + // otherwise, skip it if the type's superclass must implement any of the inherited methods + ReferenceBinding superclass = this.type.superclass(); + ReferenceBinding declaringClass = abstractMethod.declaringClass; + if (declaringClass.isClass()) { + while (superclass.isAbstract() && superclass != declaringClass) + superclass = superclass.superclass(); // find the first concrete superclass or the abstract declaringClass + } else { + if (this.type.implementsInterface(declaringClass, false)) { + if (this.type.isAbstract()) return false; // leave it for the subclasses + if (!superclass.implementsInterface(declaringClass, true)) // only if a superclass does not also implement the interface + return true; + } + while (superclass.isAbstract() && !superclass.implementsInterface(declaringClass, false)) + superclass = superclass.superclass(); // find the first concrete superclass or the superclass which implements the interface + } + return superclass.isAbstract(); // if it is a concrete class then we have already reported problem against it +} +private ProblemReporter problemReporter() { + return this.type.scope.problemReporter(); +} +private ProblemReporter problemReporter(MethodBinding currentMethod) { + ProblemReporter reporter = problemReporter(); + if (currentMethod.declaringClass == type) // only report against the currentMethod if its implemented by the type + reporter.referenceContext = currentMethod.sourceMethod(); + return reporter; +} +ReferenceBinding[] resolvedExceptionTypesFor(MethodBinding method) { + ReferenceBinding[] exceptions = method.thrownExceptions; + if ((method.modifiers & CompilerModifiers.AccUnresolved) == 0) + return exceptions; + + if (!(method.declaringClass instanceof BinaryTypeBinding)) + return TypeConstants.NoExceptions; // safety check + BinaryTypeBinding binaryType = (BinaryTypeBinding) method.declaringClass; + + for (int i = exceptions.length; --i >= 0;) + if (exceptions[i] instanceof UnresolvedReferenceBinding) + exceptions[i] = (ReferenceBinding) binaryType.resolveType(exceptions[i]); + return exceptions; +} +private ReferenceBinding runtimeException() { + if (runtimeException == null) + this.runtimeException = this.type.scope.getJavaLangRuntimeException(); + return runtimeException; +} +public void verify(SourceTypeBinding someType) { + this.type = someType; + this.computeMethods(); + this.computeInheritedMethods(); + this.checkMethods(); +} +public String toString() { + StringBuffer buffer = new StringBuffer(10); + buffer.append("MethodVerifier for type: "); //$NON-NLS-1$ + buffer.append(type.readableName()); + buffer.append('\n'); + buffer.append("\t-inherited methods: "); //$NON-NLS-1$ + buffer.append(this.inheritedMethods); + return buffer.toString(); +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/NestedTypeBinding.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/NestedTypeBinding.java new file mode 100644 index 0000000..8143f9b --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/NestedTypeBinding.java @@ -0,0 +1,217 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +public class NestedTypeBinding extends SourceTypeBinding { + + public SourceTypeBinding enclosingType; + + public SyntheticArgumentBinding[] enclosingInstances; + public SyntheticArgumentBinding[] outerLocalVariables; + public int enclosingInstancesSlotSize; // amount of slots used by synthetic enclosing instances + public int outerLocalVariablesSlotSize; // amount of slots used by synthetic outer local variables + + public NestedTypeBinding(char[][] typeName, ClassScope scope, SourceTypeBinding enclosingType) { + super(typeName, enclosingType.fPackage, scope); + this.tagBits |= IsNestedType; + this.enclosingType = enclosingType; + } + + /* Add a new synthetic argument for . + * Answer the new argument or the existing argument if one already existed. + */ + public SyntheticArgumentBinding addSyntheticArgument(LocalVariableBinding actualOuterLocalVariable) { + SyntheticArgumentBinding synthLocal = null; + + if (outerLocalVariables == null) { + synthLocal = new SyntheticArgumentBinding(actualOuterLocalVariable); + outerLocalVariables = new SyntheticArgumentBinding[] {synthLocal}; + } else { + int size = outerLocalVariables.length; + int newArgIndex = size; + for (int i = size; --i >= 0;) { // must search backwards + if (outerLocalVariables[i].actualOuterLocalVariable == actualOuterLocalVariable) + return outerLocalVariables[i]; // already exists + if (outerLocalVariables[i].id > actualOuterLocalVariable.id) + newArgIndex = i; + } + SyntheticArgumentBinding[] synthLocals = new SyntheticArgumentBinding[size + 1]; + System.arraycopy(outerLocalVariables, 0, synthLocals, 0, newArgIndex); + synthLocals[newArgIndex] = synthLocal = new SyntheticArgumentBinding(actualOuterLocalVariable); + System.arraycopy(outerLocalVariables, newArgIndex, synthLocals, newArgIndex + 1, size - newArgIndex); + outerLocalVariables = synthLocals; + } + //System.out.println("Adding synth arg for local var: " + new String(actualOuterLocalVariable.name) + " to: " + new String(this.readableName())); + if (scope.referenceCompilationUnit().isPropagatingInnerClassEmulation) + this.updateInnerEmulationDependents(); + return synthLocal; + } + + /* Add a new synthetic argument for . + * Answer the new argument or the existing argument if one already existed. + */ + public SyntheticArgumentBinding addSyntheticArgument(ReferenceBinding targetEnclosingType) { + SyntheticArgumentBinding synthLocal = null; + if (enclosingInstances == null) { + synthLocal = new SyntheticArgumentBinding(targetEnclosingType); + enclosingInstances = new SyntheticArgumentBinding[] {synthLocal}; + } else { + int size = enclosingInstances.length; + int newArgIndex = size; + for (int i = size; --i >= 0;) { + if (enclosingInstances[i].type == targetEnclosingType) + return enclosingInstances[i]; // already exists + if (this.enclosingType() == targetEnclosingType) + newArgIndex = 0; + } + SyntheticArgumentBinding[] newInstances = new SyntheticArgumentBinding[size + 1]; + System.arraycopy(enclosingInstances, 0, newInstances, newArgIndex == 0 ? 1 : 0, size); + newInstances[newArgIndex] = synthLocal = new SyntheticArgumentBinding(targetEnclosingType); + enclosingInstances = newInstances; + } + //System.out.println("Adding synth arg for enclosing type: " + new String(enclosingType.readableName()) + " to: " + new String(this.readableName())); + if (scope.referenceCompilationUnit().isPropagatingInnerClassEmulation) + this.updateInnerEmulationDependents(); + return synthLocal; + } + + /* Add a new synthetic argument and field for . + * Answer the new argument or the existing argument if one already existed. + */ + public SyntheticArgumentBinding addSyntheticArgumentAndField(LocalVariableBinding actualOuterLocalVariable) { + SyntheticArgumentBinding synthLocal = addSyntheticArgument(actualOuterLocalVariable); + if (synthLocal == null) return null; + + if (synthLocal.matchingField == null) + synthLocal.matchingField = addSyntheticField(actualOuterLocalVariable); + return synthLocal; + } + + /* Add a new synthetic argument and field for . + * Answer the new argument or the existing argument if one already existed. + */ + public SyntheticArgumentBinding addSyntheticArgumentAndField(ReferenceBinding targetEnclosingType) { + SyntheticArgumentBinding synthLocal = addSyntheticArgument(targetEnclosingType); + if (synthLocal == null) return null; + + if (synthLocal.matchingField == null) + synthLocal.matchingField = addSyntheticField(targetEnclosingType); + return synthLocal; + } + + /** + * Compute the resolved positions for all the synthetic arguments + */ + final public void computeSyntheticArgumentSlotSizes() { + + int slotSize = 0; + // insert enclosing instances first, followed by the outerLocals + int enclosingInstancesCount = this.enclosingInstances == null ? 0 : this.enclosingInstances.length; + for (int i = 0; i < enclosingInstancesCount; i++){ + SyntheticArgumentBinding argument = this.enclosingInstances[i]; + // position the enclosing instance synthetic arg + argument.resolvedPosition = slotSize + 1; // shift by 1 to leave room for aload0==this + if (slotSize + 1 > 0xFF) { // no more than 255 words of arguments + this.scope.problemReporter().noMoreAvailableSpaceForArgument(argument, this.scope.referenceType()); + } + if ((argument.type == LongBinding) || (argument.type == DoubleBinding)){ + slotSize += 2; + } else { + slotSize ++; + } + } + this.enclosingInstancesSlotSize = slotSize; + + slotSize = 0; // reset, outer local are not positionned yet, since will be appended to user arguments + int outerLocalsCount = this.outerLocalVariables == null ? 0 : this.outerLocalVariables.length; + for (int i = 0; i < outerLocalsCount; i++){ + SyntheticArgumentBinding argument = this.outerLocalVariables[i]; + // do NOT position the outerlocal synthetic arg yet, since will be appended to user arguments + if ((argument.type == LongBinding) || (argument.type == DoubleBinding)){ + slotSize += 2; + } else { + slotSize ++; + } + } + this.outerLocalVariablesSlotSize = slotSize; + } + + /* Answer the receiver's enclosing type... null if the receiver is a top level type. + */ + public ReferenceBinding enclosingType() { + + return enclosingType; + } + + /* Answer the synthetic argument for or null if one does not exist. + */ + public SyntheticArgumentBinding getSyntheticArgument(LocalVariableBinding actualOuterLocalVariable) { + + if (outerLocalVariables == null) return null; // is null if no outer local variables are known + + for (int i = outerLocalVariables.length; --i >= 0;) + if (outerLocalVariables[i].actualOuterLocalVariable == actualOuterLocalVariable) + return outerLocalVariables[i]; + return null; + } + + public SyntheticArgumentBinding[] syntheticEnclosingInstances() { + return enclosingInstances; // is null if no enclosing instances are required + } + + public ReferenceBinding[] syntheticEnclosingInstanceTypes() { + if (enclosingInstances == null) + return null; + + int length = enclosingInstances.length; + ReferenceBinding types[] = new ReferenceBinding[length]; + for (int i = 0; i < length; i++) + types[i] = (ReferenceBinding) enclosingInstances[i].type; + return types; + } + + public SyntheticArgumentBinding[] syntheticOuterLocalVariables() { + + return outerLocalVariables; // is null if no outer locals are required + } + + /* + * Trigger the dependency mechanism forcing the innerclass emulation + * to be propagated to all dependent source types. + */ + public void updateInnerEmulationDependents() { + // nothing to do in general, only local types are doing anything + } + + /* Answer the synthetic argument for or null if one does not exist. + */ + public SyntheticArgumentBinding getSyntheticArgument(ReferenceBinding targetEnclosingType, boolean onlyExactMatch) { + + if (enclosingInstances == null) return null; // is null if no enclosing instances are known + + // exact match + for (int i = enclosingInstances.length; --i >= 0;) + if (enclosingInstances[i].type == targetEnclosingType) + if (enclosingInstances[i].actualOuterLocalVariable == null) + return enclosingInstances[i]; + + // type compatibility : to handle cases such as + // class T { class M{}} + // class S extends T { class N extends M {}} --> need to use S as a default enclosing instance for the super constructor call in N(). + if (!onlyExactMatch){ + for (int i = enclosingInstances.length; --i >= 0;) + if (enclosingInstances[i].actualOuterLocalVariable == null) + if (targetEnclosingType.isSuperclassOf((ReferenceBinding) enclosingInstances[i].type)) + return enclosingInstances[i]; + } + return null; + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java new file mode 100644 index 0000000..ee68a49 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java @@ -0,0 +1,198 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.util.HashtableOfPackage; +import org.eclipse.jdt.internal.compiler.util.HashtableOfType; + +public class PackageBinding extends Binding implements TypeConstants { + public char[][] compoundName; + PackageBinding parent; + LookupEnvironment environment; + HashtableOfType knownTypes; + HashtableOfPackage knownPackages; +protected PackageBinding() { + // for creating problem package +} +public PackageBinding(char[][] compoundName, PackageBinding parent, LookupEnvironment environment) { + this.compoundName = compoundName; + this.parent = parent; + this.environment = environment; + this.knownTypes = null; // initialized if used... class counts can be very large 300-600 + this.knownPackages = new HashtableOfPackage(3); // sub-package counts are typically 0-3 +} +public PackageBinding(char[] topLevelPackageName, LookupEnvironment environment) { + this(new char[][] {topLevelPackageName}, null, environment); +} +/* Create the default package. +*/ + +public PackageBinding(LookupEnvironment environment) { + this(CharOperation.NO_CHAR_CHAR, null, environment); +} +private void addNotFoundPackage(char[] simpleName) { + knownPackages.put(simpleName, LookupEnvironment.TheNotFoundPackage); +} +private void addNotFoundType(char[] simpleName) { + if (knownTypes == null) + knownTypes = new HashtableOfType(25); + knownTypes.put(simpleName, LookupEnvironment.TheNotFoundType); +} +void addPackage(PackageBinding element) { + knownPackages.put(element.compoundName[element.compoundName.length - 1], element); +} +void addType(ReferenceBinding element) { + if (knownTypes == null) + knownTypes = new HashtableOfType(25); + knownTypes.put(element.compoundName[element.compoundName.length - 1], element); +} +/* API +* Answer the receiver's binding type from Binding.BindingID. +*/ + +public final int bindingType() { + return PACKAGE; +} +private PackageBinding findPackage(char[] name) { + if (!environment.isPackage(this.compoundName, name)) + return null; + + char[][] subPkgCompoundName = CharOperation.arrayConcat(this.compoundName, name); + PackageBinding subPackageBinding = new PackageBinding(subPkgCompoundName, this, environment); + addPackage(subPackageBinding); + return subPackageBinding; +} +/* Answer the subpackage named name; ask the oracle for the package if its not in the cache. +* Answer null if it could not be resolved. +* +* NOTE: This should only be used when we know there is NOT a type with the same name. +*/ + +PackageBinding getPackage(char[] name) { + PackageBinding binding = getPackage0(name); + if (binding != null) { + if (binding == LookupEnvironment.TheNotFoundPackage) + return null; + else + return binding; + } + if ((binding = findPackage(name)) != null) + return binding; + + // not found so remember a problem package binding in the cache for future lookups + addNotFoundPackage(name); + return null; +} +/* Answer the subpackage named name if it exists in the cache. +* Answer theNotFoundPackage if it could not be resolved the first time +* it was looked up, otherwise answer null. +* +* NOTE: Senders must convert theNotFoundPackage into a real problem +* package if its to returned. +*/ + +PackageBinding getPackage0(char[] name) { + return knownPackages.get(name); +} +/* Answer the type named name; ask the oracle for the type if its not in the cache. +* Answer a NotVisible problem type if the type is not visible from the invocationPackage. +* Answer null if it could not be resolved. +* +* NOTE: This should only be used by source types/scopes which know there is NOT a +* package with the same name. +*/ + +ReferenceBinding getType(char[] name) { + ReferenceBinding binding = getType0(name); + if (binding == null) { + if ((binding = environment.askForType(this, name)) == null) { + // not found so remember a problem type binding in the cache for future lookups + addNotFoundType(name); + return null; + } + } + + if (binding == LookupEnvironment.TheNotFoundType) + return null; + if (binding instanceof UnresolvedReferenceBinding) + binding = ((UnresolvedReferenceBinding) binding).resolve(environment); + if (binding.isNestedType()) + return new ProblemReferenceBinding(name, InternalNameProvided); + return binding; +} +/* Answer the type named name if it exists in the cache. +* Answer theNotFoundType if it could not be resolved the first time +* it was looked up, otherwise answer null. +* +* NOTE: Senders must convert theNotFoundType into a real problem +* reference type if its to returned. +*/ + +ReferenceBinding getType0(char[] name) { + if (knownTypes == null) + return null; + return knownTypes.get(name); +} +/* Answer the package or type named name; ask the oracle if it is not in the cache. +* Answer null if it could not be resolved. +* +* When collisions exist between a type name & a package name, answer the type. +* Treat the package as if it does not exist... a problem was already reported when the type was defined. +* +* NOTE: no visibility checks are performed. +* THIS SHOULD ONLY BE USED BY SOURCE TYPES/SCOPES. +*/ + +public Binding getTypeOrPackage(char[] name) { + ReferenceBinding typeBinding = getType0(name); + if (typeBinding != null && typeBinding != LookupEnvironment.TheNotFoundType) { + if (typeBinding instanceof UnresolvedReferenceBinding) + typeBinding = ((UnresolvedReferenceBinding) typeBinding).resolve(environment); + if (typeBinding.isNestedType()) + return new ProblemReferenceBinding(name, InternalNameProvided); + return typeBinding; + } + + PackageBinding packageBinding = getPackage0(name); + if (packageBinding != null && packageBinding != LookupEnvironment.TheNotFoundPackage) + return packageBinding; + + if (typeBinding == null) { // have not looked for it before + if ((typeBinding = environment.askForType(this, name)) != null) { + if (typeBinding.isNestedType()) + return new ProblemReferenceBinding(name, InternalNameProvided); + return typeBinding; + } + + // Since name could not be found, add a problem binding + // to the collections so it will be reported as an error next time. + addNotFoundType(name); + } + + if (packageBinding == null) { // have not looked for it before + if ((packageBinding = findPackage(name)) != null) + return packageBinding; + addNotFoundPackage(name); + } + + return null; +} +public char[] readableName() /*java.lang*/ { + return CharOperation.concatWith(compoundName, '.'); +} +public String toString() { + if (compoundName == CharOperation.NO_CHAR_CHAR) + return "The Default Package"; //$NON-NLS-1$ + else + return "package " + ((compoundName != null) ? CharOperation.toString(compoundName) : "UNNAMED"); //$NON-NLS-1$ //$NON-NLS-2$ +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/ProblemBinding.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/ProblemBinding.java new file mode 100644 index 0000000..c4fab5f --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/ProblemBinding.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +import org.eclipse.jdt.core.compiler.CharOperation; + +public class ProblemBinding extends Binding { + public char[] name; + public ReferenceBinding searchType; + private int problemId; +// NOTE: must only answer the subset of the name related to the problem + +public ProblemBinding(char[][] compoundName, int problemId) { + this(CharOperation.concatWith(compoundName, '.'), problemId); +} +// NOTE: must only answer the subset of the name related to the problem + +public ProblemBinding(char[][] compoundName, ReferenceBinding searchType, int problemId) { + this(CharOperation.concatWith(compoundName, '.'), searchType, problemId); +} +ProblemBinding(char[] name, int problemId) { + this.name = name; + this.problemId = problemId; +} +ProblemBinding(char[] name, ReferenceBinding searchType, int problemId) { + this(name, problemId); + this.searchType = searchType; +} +/* API +* Answer the receiver's binding type from Binding.BindingID. +*/ + +public final int bindingType() { + return VARIABLE | TYPE; +} +/* API +* Answer the problem id associated with the receiver. +* NoError if the receiver is a valid binding. +*/ + +public final int problemId() { + return problemId; +} +public char[] readableName() { + return name; +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/ProblemFieldBinding.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/ProblemFieldBinding.java new file mode 100644 index 0000000..ec3012d --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/ProblemFieldBinding.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +import org.eclipse.jdt.core.compiler.CharOperation; + +public class ProblemFieldBinding extends FieldBinding { + private int problemId; + public FieldBinding closestMatch; + +// NOTE: must only answer the subset of the name related to the problem + +public ProblemFieldBinding(ReferenceBinding declaringClass, char[][] compoundName, int problemId) { + this(null, declaringClass, CharOperation.concatWith(compoundName, '.'), problemId); +} +public ProblemFieldBinding(ReferenceBinding declaringClass, char[] name, int problemId) { + this(null, declaringClass, name, problemId); +} +public ProblemFieldBinding(FieldBinding closestMatch, ReferenceBinding declaringClass, char[] name, int problemId) { + this.closestMatch = closestMatch; + this.declaringClass = declaringClass; + this.name = name; + this.problemId = problemId; +} +/* API +* Answer the problem id associated with the receiver. +* NoError if the receiver is a valid binding. +*/ + +public final int problemId() { + return problemId; +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/ProblemMethodBinding.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/ProblemMethodBinding.java new file mode 100644 index 0000000..71f0547 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/ProblemMethodBinding.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +public class ProblemMethodBinding extends MethodBinding { + private int problemId; + public MethodBinding closestMatch; +public ProblemMethodBinding(char[] selector, TypeBinding[] args, int problemId) { + this.selector = selector; + this.parameters = (args == null || args.length == 0) ? NoParameters : args; + this.problemId = problemId; +} +public ProblemMethodBinding(char[] selector, TypeBinding[] args, ReferenceBinding declaringClass, int problemId) { + this.selector = selector; + this.parameters = (args == null || args.length == 0) ? NoParameters : args; + this.declaringClass = declaringClass; + this.problemId = problemId; +} +public ProblemMethodBinding(MethodBinding closestMatch, char[] selector, TypeBinding[] args, int problemId) { + this(selector, args, problemId); + this.closestMatch = closestMatch; + if (closestMatch != null) this.declaringClass = closestMatch.declaringClass; +} +/* API +* Answer the problem id associated with the receiver. +* NoError if the receiver is a valid binding. +*/ + +public final int problemId() { + return problemId; +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/ProblemPackageBinding.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/ProblemPackageBinding.java new file mode 100644 index 0000000..c2b2367 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/ProblemPackageBinding.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +public class ProblemPackageBinding extends PackageBinding { + private int problemId; +// NOTE: must only answer the subset of the name related to the problem + +ProblemPackageBinding(char[][] compoundName, int problemId) { + this.compoundName = compoundName; + this.problemId = problemId; +} +ProblemPackageBinding(char[] name, int problemId) { + this(new char[][] {name}, problemId); +} +/* API +* Answer the problem id associated with the receiver. +* NoError if the receiver is a valid binding. +*/ + +public final int problemId() { + return problemId; +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/ProblemReasons.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/ProblemReasons.java new file mode 100644 index 0000000..b34f200 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/ProblemReasons.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +public interface ProblemReasons { + final int NoError = 0; + final int NotFound = 1; + final int NotVisible = 2; + final int Ambiguous = 3; + final int InternalNameProvided = 4; // used if an internal name is used in source + final int InheritedNameHidesEnclosingName = 5; + final int NonStaticReferenceInConstructorInvocation = 6; + final int NonStaticReferenceInStaticContext = 7; + final int ReceiverTypeNotVisible = 8; +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/ProblemReferenceBinding.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/ProblemReferenceBinding.java new file mode 100644 index 0000000..7225ba7 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/ProblemReferenceBinding.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +public class ProblemReferenceBinding extends ReferenceBinding { + public ReferenceBinding original; + private int problemId; +// NOTE: must only answer the subset of the name related to the problem + +public ProblemReferenceBinding(char[][] compoundName, int problemId) { + this(compoundName, null, problemId); +} +public ProblemReferenceBinding(char[] name, int problemId) { + this(new char[][] {name}, null, problemId); +} + +public ProblemReferenceBinding(char[][] compoundName, ReferenceBinding original, int problemId) { + this.compoundName = compoundName; + this.original = original; + this.problemId = problemId; +} +public ProblemReferenceBinding(char[] name, ReferenceBinding original, int problemId) { + this(new char[][] {name}, original, problemId); +} +/* API +* Answer the problem id associated with the receiver. +* NoError if the receiver is a valid binding. +*/ + +public final int problemId() { + return problemId; +} + +/** + * @see org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding#shortReadableName() + */ +public char[] shortReadableName() { + return readableName(); +} + +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java new file mode 100644 index 0000000..6cda282 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java @@ -0,0 +1,589 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.env.IDependent; + +/* +Not all fields defined by this type (& its subclasses) are initialized when it is created. +Some are initialized only when needed. + +Accessors have been provided for some public fields so all TypeBindings have the same API... +but access public fields directly whenever possible. +Non-public fields have accessors which should be used everywhere you expect the field to be initialized. + +null is NOT a valid value for a non-public field... it just means the field is not initialized. +*/ + +abstract public class ReferenceBinding extends TypeBinding implements IDependent { + public char[][] compoundName; + public char[] sourceName; + public int modifiers; + public PackageBinding fPackage; + + char[] fileName; + char[] constantPoolName; + char[] signature; + +public FieldBinding[] availableFields() { + return fields(); +} + +public MethodBinding[] availableMethods() { + return methods(); +} +/* Answer true if the receiver can be instantiated +*/ + +public boolean canBeInstantiated() { + return !(isAbstract() || isInterface()); +} +/* Answer true if the receiver is visible to the invocationPackage. +*/ + +public final boolean canBeSeenBy(PackageBinding invocationPackage) { + if (isPublic()) return true; + if (isPrivate()) return false; + + // isProtected() or isDefault() + return invocationPackage == fPackage; +} +/* Answer true if the receiver is visible to the receiverType and the invocationType. +*/ + +public final boolean canBeSeenBy(ReferenceBinding receiverType, SourceTypeBinding invocationType) { + if (isPublic()) return true; + + if (invocationType == this && invocationType == receiverType) return true; + + if (isProtected()) { + + // answer true if the invocationType is the declaringClass or they are in the same package + // OR the invocationType is a subclass of the declaringClass + // AND the invocationType is the invocationType or its subclass + // OR the type is a static method accessed directly through a type + // OR previous assertions are true for one of the enclosing type + if (invocationType == this) return true; + if (invocationType.fPackage == fPackage) return true; + + ReferenceBinding currentType = invocationType; + ReferenceBinding declaringClass = enclosingType(); // protected types always have an enclosing one + if (declaringClass == null) return false; // could be null if incorrect top-level protected type + //int depth = 0; + do { + if (declaringClass == invocationType) return true; + if (declaringClass.isSuperclassOf(currentType)) return true; + //depth++; + currentType = currentType.enclosingType(); + } while (currentType != null); + return false; + } + + if (isPrivate()) { + // answer true if the receiverType is the receiver or its enclosingType + // AND the invocationType and the receiver have a common enclosingType + if (!(receiverType == this || receiverType == enclosingType())) return false; + + if (invocationType != this) { + ReferenceBinding outerInvocationType = invocationType; + ReferenceBinding temp = outerInvocationType.enclosingType(); + while (temp != null) { + outerInvocationType = temp; + temp = temp.enclosingType(); + } + + ReferenceBinding outerDeclaringClass = this; + temp = outerDeclaringClass.enclosingType(); + while (temp != null) { + outerDeclaringClass = temp; + temp = temp.enclosingType(); + } + if (outerInvocationType != outerDeclaringClass) return false; + } + return true; + } + + // isDefault() + if (invocationType.fPackage != fPackage) return false; + + ReferenceBinding type = receiverType; + ReferenceBinding declaringClass = enclosingType() == null ? this : enclosingType(); + do { + if (declaringClass == type) return true; + if (fPackage != type.fPackage) return false; + } while ((type = type.superclass()) != null); + return false; +} +/* + * Answer true if the receiver is visible to the type provided by the scope. + */ + +public final boolean canBeSeenBy(Scope scope) { + + if (isPublic()) return true; + + if (scope.kind == Scope.COMPILATION_UNIT_SCOPE){ + return this.canBeSeenBy(((CompilationUnitScope)scope).fPackage); + } + + SourceTypeBinding invocationType = scope.enclosingSourceType(); + if (invocationType == this) return true; + + if (isProtected()) { + // answer true if the invocationType is the declaringClass or they are in the same package + // OR the invocationType is a subclass of the declaringClass + // AND the invocationType is the invocationType or its subclass + // OR the type is a static method accessed directly through a type + // OR previous assertions are true for one of the enclosing type + if (invocationType.fPackage == fPackage) return true; + + ReferenceBinding currentType = invocationType; + ReferenceBinding declaringClass = enclosingType(); // protected types always have an enclosing one + if (declaringClass == null) return false; // could be null if incorrect top-level protected type + // int depth = 0; + do { + if (declaringClass == invocationType) return true; + if (declaringClass.isSuperclassOf(currentType)) return true; + // depth++; + currentType = currentType.enclosingType(); + } while (currentType != null); + return false; + } + if (isPrivate()) { + // answer true if the receiver and the invocationType have a common enclosingType + // already know they are not the identical type + ReferenceBinding outerInvocationType = invocationType; + ReferenceBinding temp = outerInvocationType.enclosingType(); + while (temp != null) { + outerInvocationType = temp; + temp = temp.enclosingType(); + } + + ReferenceBinding outerDeclaringClass = this; + temp = outerDeclaringClass.enclosingType(); + while (temp != null) { + outerDeclaringClass = temp; + temp = temp.enclosingType(); + } + return outerInvocationType == outerDeclaringClass; + } + + // isDefault() + return invocationType.fPackage == fPackage; +} +public void computeId() { + if (compoundName.length != 3) { + if (compoundName.length == 4 && CharOperation.equals(JAVA_LANG_REFLECT_CONSTRUCTOR, compoundName)) + id = T_JavaLangReflectConstructor; + return; + } + + if (!CharOperation.equals(JAVA, compoundName[0])) + return; + + // remaining types MUST be in java.*.* + if (!CharOperation.equals(LANG, compoundName[1])) { + if (CharOperation.equals(JAVA_IO_PRINTSTREAM, compoundName)) + id = T_JavaIoPrintStream; + else if (CharOperation.equals(JAVA_IO_SERIALIZABLE, compoundName)) + id = T_JavaIoSerializable; + return; + } + + // remaining types MUST be in java.lang.* + char[] typeName = compoundName[2]; + if (typeName.length == 0) return; // just to be safe + switch (typeName[0]) { + case 'A' : + if (CharOperation.equals(typeName, JAVA_LANG_ASSERTIONERROR[2])) + id = T_JavaLangAssertionError; + return; + case 'B' : + if (CharOperation.equals(typeName, JAVA_LANG_BOOLEAN[2])) + id = T_JavaLangBoolean; + else if (CharOperation.equals(typeName, JAVA_LANG_BYTE[2])) + id = T_JavaLangByte; + return; + case 'C' : + if (CharOperation.equals(typeName, JAVA_LANG_CHARACTER[2])) + id = T_JavaLangCharacter; + else if (CharOperation.equals(typeName, JAVA_LANG_CLASS[2])) + id = T_JavaLangClass; + else if (CharOperation.equals(typeName, JAVA_LANG_CLASSNOTFOUNDEXCEPTION[2])) + id = T_JavaLangClassNotFoundException; + else if (CharOperation.equals(typeName, JAVA_LANG_CLONEABLE[2])) + id = T_JavaLangCloneable; + return; + case 'D' : + if (CharOperation.equals(typeName, JAVA_LANG_DOUBLE[2])) + id = T_JavaLangDouble; + return; + case 'E' : + if (CharOperation.equals(typeName, JAVA_LANG_ERROR[2])) + id = T_JavaLangError; + else if (CharOperation.equals(typeName, JAVA_LANG_EXCEPTION[2])) + id = T_JavaLangException; + return; + case 'F' : + if (CharOperation.equals(typeName, JAVA_LANG_FLOAT[2])) + id = T_JavaLangFloat; + return; + case 'I' : + if (CharOperation.equals(typeName, JAVA_LANG_INTEGER[2])) + id = T_JavaLangInteger; + return; + case 'L' : + if (CharOperation.equals(typeName, JAVA_LANG_LONG[2])) + id = T_JavaLangLong; + return; + case 'N' : + if (CharOperation.equals(typeName, JAVA_LANG_NOCLASSDEFERROR[2])) + id = T_JavaLangNoClassDefError; + return; + case 'O' : + if (CharOperation.equals(typeName, JAVA_LANG_OBJECT[2])) + id = T_JavaLangObject; + return; + case 'S' : + if (CharOperation.equals(typeName, JAVA_LANG_STRING[2])) + id = T_JavaLangString; + else if (CharOperation.equals(typeName, JAVA_LANG_STRINGBUFFER[2])) + id = T_JavaLangStringBuffer; + else if (CharOperation.equals(typeName, JAVA_LANG_SYSTEM[2])) + id = T_JavaLangSystem; + else if (CharOperation.equals(typeName, JAVA_LANG_SHORT[2])) + id = T_JavaLangShort; + return; + case 'T' : + if (CharOperation.equals(typeName, JAVA_LANG_THROWABLE[2])) + id = T_JavaLangThrowable; + return; + case 'V' : + if (CharOperation.equals(typeName, JAVA_LANG_VOID[2])) + id = T_JavaLangVoid; + return; + } +} +/* Answer the receiver's constant pool name. +* +* NOTE: This method should only be used during/after code gen. +*/ + +public char[] constantPoolName() /* java/lang/Object */ { + if (constantPoolName != null) return constantPoolName; + return constantPoolName = CharOperation.concatWith(compoundName, '/'); +} +String debugName() { + return (compoundName != null) ? new String(readableName()) : "UNNAMED TYPE"; //$NON-NLS-1$ +} +public final int depth() { + int depth = 0; + ReferenceBinding current = this; + while ((current = current.enclosingType()) != null) + depth++; + return depth; +} +/* Answer the receiver's enclosing type... null if the receiver is a top level type. +*/ + +public ReferenceBinding enclosingType() { + return null; +} +public final ReferenceBinding enclosingTypeAt(int relativeDepth) { + ReferenceBinding current = this; + while (relativeDepth-- > 0 && current != null) + current = current.enclosingType(); + return current; +} +public int fieldCount() { + return fields().length; +} +public FieldBinding[] fields() { + return NoFields; +} +public final int getAccessFlags() { + return modifiers & AccJustFlag; +} +public MethodBinding getExactConstructor(TypeBinding[] argumentTypes) { + return null; +} +public MethodBinding getExactMethod(char[] selector, TypeBinding[] argumentTypes) { + return null; +} +public FieldBinding getField(char[] fieldName, boolean needResolve) { + return null; +} +/** + * Answer the file name which defines the type. + * + * The path part (optional) must be separated from the actual + * file proper name by a java.io.File.separator. + * + * The proper file name includes the suffix extension (e.g. ".java") + * + * e.g. "c:/com/ibm/compiler/java/api/Compiler.java" + */ + +public char[] getFileName() { + return fileName; +} +public ReferenceBinding getMemberType(char[] typeName) { + ReferenceBinding[] memberTypes = memberTypes(); + for (int i = memberTypes.length; --i >= 0;) + if (CharOperation.equals(memberTypes[i].sourceName, typeName)) + return memberTypes[i]; + return null; +} +public MethodBinding[] getMethods(char[] selector) { + return NoMethods; +} +public PackageBinding getPackage() { + return fPackage; +} +public boolean hasMemberTypes() { + return false; +} +/* Answer true if the receiver implements anInterface or is identical to anInterface. +* If searchHierarchy is true, then also search the receiver's superclasses. +* +* NOTE: Assume that anInterface is an interface. +*/ + +public boolean implementsInterface(ReferenceBinding anInterface, boolean searchHierarchy) { + if (this == anInterface) + return true; + + ReferenceBinding[][] interfacesToVisit = new ReferenceBinding[5][]; + int lastPosition = -1; + ReferenceBinding currentType = this; + do { + ReferenceBinding[] itsInterfaces = currentType.superInterfaces(); + if (itsInterfaces != NoSuperInterfaces) { + if (++lastPosition == interfacesToVisit.length) + System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition); + interfacesToVisit[lastPosition] = itsInterfaces; + } + } while (searchHierarchy && (currentType = currentType.superclass()) != null); + + for (int i = 0; i <= lastPosition; i++) { + ReferenceBinding[] interfaces = interfacesToVisit[i]; + for (int j = 0, length = interfaces.length; j < length; j++) { + if ((currentType = interfaces[j]) == anInterface) + return true; + + ReferenceBinding[] itsInterfaces = currentType.superInterfaces(); + if (itsInterfaces != NoSuperInterfaces) { + if (++lastPosition == interfacesToVisit.length) + System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition); + interfacesToVisit[lastPosition] = itsInterfaces; + } + } + } + return false; +} +// Internal method... assume its only sent to classes NOT interfaces + +boolean implementsMethod(MethodBinding method) { + ReferenceBinding type = this; + while (type != null) { + MethodBinding[] methods = type.getMethods(method.selector); + for (int i = methods.length; --i >= 0;) + if (methods[i].areParametersEqual(method)) + return true; + type = type.superclass(); + } + return false; +} +/* Answer true if the receiver is an abstract type +*/ + +public final boolean isAbstract() { + return (modifiers & AccAbstract) != 0; +} +public final boolean isAnonymousType() { + return (tagBits & IsAnonymousType) != 0; +} +public final boolean isBinaryBinding() { + return (tagBits & IsBinaryBinding) != 0; +} +public final boolean isClass() { + return (modifiers & AccInterface) == 0; +} +/* Answer true if the receiver type can be assigned to the argument type (right) +*/ + +public boolean isCompatibleWith(TypeBinding right) { + if (right == this) + return true; + if (right.id == T_Object) + return true; + if (!(right instanceof ReferenceBinding)) + return false; + + ReferenceBinding referenceBinding = (ReferenceBinding) right; + if (referenceBinding.isInterface()) + return implementsInterface(referenceBinding, true); + if (isInterface()) // Explicit conversion from an interface to a class is not allowed + return false; + return referenceBinding.isSuperclassOf(this); +} +/* Answer true if the receiver has default visibility +*/ + +public final boolean isDefault() { + return (modifiers & (AccPublic | AccProtected | AccPrivate)) == 0; +} +/* Answer true if the receiver is a deprecated type +*/ + +public final boolean isDeprecated() { + return (modifiers & AccDeprecated) != 0; +} +/* Answer true if the receiver is final and cannot be subclassed +*/ + +public final boolean isFinal() { + return (modifiers & AccFinal) != 0; +} +public final boolean isInterface() { + return (modifiers & AccInterface) != 0; +} +public final boolean isLocalType() { + return (tagBits & IsLocalType) != 0; +} +public final boolean isMemberType() { + return (tagBits & IsMemberType) != 0; +} +public final boolean isNestedType() { + return (tagBits & IsNestedType) != 0; +} +/* Answer true if the receiver has private visibility +*/ + +public final boolean isPrivate() { + return (modifiers & AccPrivate) != 0; +} +/* Answer true if the receiver has private visibility and is used locally +*/ + +public final boolean isPrivateUsed() { + return (modifiers & AccPrivateUsed) != 0; +} +/* Answer true if the receiver has protected visibility +*/ + +public final boolean isProtected() { + return (modifiers & AccProtected) != 0; +} +/* Answer true if the receiver has public visibility +*/ + +public final boolean isPublic() { + return (modifiers & AccPublic) != 0; +} +/* Answer true if the receiver is a static member type (or toplevel) + */ + +public final boolean isStatic() { + return (modifiers & (AccStatic | AccInterface)) != 0 || + (tagBits & IsNestedType) == 0; +} +/* Answer true if all float operations must adher to IEEE 754 float/double rules +*/ + +public final boolean isStrictfp() { + return (modifiers & AccStrictfp) != 0; +} +/* Answer true if the receiver is in the superclass hierarchy of aType +* +* NOTE: Object.isSuperclassOf(Object) -> false +*/ + +public boolean isSuperclassOf(ReferenceBinding type) { + do { + if (this == (type = type.superclass())) return true; + } while (type != null); + + return false; +} +/* Answer true if the receiver is deprecated (or any of its enclosing types) +*/ + +public final boolean isViewedAsDeprecated() { + return (modifiers & AccDeprecated) != 0 || + (modifiers & AccDeprecatedImplicitly) != 0; +} +public ReferenceBinding[] memberTypes() { + return NoMemberTypes; +} +public MethodBinding[] methods() { + return NoMethods; +} +/** +* Answer the source name for the type. +* In the case of member types, as the qualified name from its top level type. +* For example, for a member type N defined inside M & A: "A.M.N". +*/ + +public char[] qualifiedSourceName() { + if (isMemberType()) + return CharOperation.concat(enclosingType().qualifiedSourceName(), sourceName(), '.'); + return sourceName(); +} + +public char[] readableName() /*java.lang.Object*/ { + if (isMemberType()) + return CharOperation.concat(enclosingType().readableName(), sourceName, '.'); + return CharOperation.concatWith(compoundName, '.'); +} + +public char[] shortReadableName() /*Object*/ { + if (isMemberType()) + return CharOperation.concat(enclosingType().shortReadableName(), sourceName, '.'); + return sourceName; +} + +/* Answer the receiver's signature. +* +* NOTE: This method should only be used during/after code gen. +*/ + +public char[] signature() /* Ljava/lang/Object; */ { + if (signature != null) + return signature; + + return signature = CharOperation.concat('L', constantPoolName(), ';'); +} +public char[] sourceName() { + return sourceName; +} +public ReferenceBinding superclass() { + return null; +} +public ReferenceBinding[] superInterfaces() { + return NoSuperInterfaces; +} +public ReferenceBinding[] syntheticEnclosingInstanceTypes() { + if (isStatic()) return null; + + ReferenceBinding enclosingType = enclosingType(); + if (enclosingType == null) + return null; + return new ReferenceBinding[] {enclosingType}; +} +public SyntheticArgumentBinding[] syntheticOuterLocalVariables() { + return null; // is null if no enclosing instances are required +} +MethodBinding[] unResolvedMethods() { // for the MethodVerifier so it doesn't resolve types + return methods(); +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/Scope.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/Scope.java new file mode 100644 index 0000000..bfbb0b5 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/Scope.java @@ -0,0 +1,2000 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.ast.*; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; +import org.eclipse.jdt.internal.compiler.problem.AbortCompilation; +import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; +import org.eclipse.jdt.internal.compiler.util.HashtableOfObject; +import org.eclipse.jdt.internal.compiler.util.ObjectVector; + +public abstract class Scope + implements BaseTypes, BindingIds, CompilerModifiers, ProblemReasons, TagBits, TypeConstants, TypeIds { + + public final static int BLOCK_SCOPE = 1; + public final static int METHOD_SCOPE = 2; + public final static int CLASS_SCOPE = 3; + public final static int COMPILATION_UNIT_SCOPE = 4; + + public int kind; + public Scope parent; + + protected Scope(int kind, Scope parent) { + this.kind = kind; + this.parent = parent; + } + + /* Answer an int describing the relationship between the given types. + * + * NotRelated + * EqualOrMoreSpecific : left is compatible with right + * MoreGeneric : right is compatible with left + */ + public static int compareTypes(TypeBinding left, TypeBinding right) { + if (left.isCompatibleWith(right)) + return EqualOrMoreSpecific; + if (right.isCompatibleWith(left)) + return MoreGeneric; + return NotRelated; + } + + // Internal use only + protected final boolean areParametersAssignable(TypeBinding[] parameters, TypeBinding[] arguments) { + if (parameters == arguments) + return true; + + int length = parameters.length; + if (length != arguments.length) + return false; + + for (int i = 0; i < length; i++) + if (parameters[i] != arguments[i]) + if (!arguments[i].isCompatibleWith(parameters[i])) + return false; + return true; + } + + public final ClassScope classScope() { + Scope scope = this; + do { + if (scope instanceof ClassScope) + return (ClassScope) scope; + scope = scope.parent; + } while (scope != null); + return null; + } + + /* Answer an int describing the relationship between the given type and unchecked exceptions. + * + * NotRelated + * EqualOrMoreSpecific : type is known for sure to be an unchecked exception type + * MoreGeneric : type is a supertype of an actual unchecked exception type + */ + public int compareUncheckedException(ReferenceBinding type) { + int comparison = compareTypes(type, getJavaLangRuntimeException()); + if (comparison != 0) return comparison; + return compareTypes(type, getJavaLangError()); + } + + public final CompilationUnitScope compilationUnitScope() { + Scope lastScope = null; + Scope scope = this; + do { + lastScope = scope; + scope = scope.parent; + } while (scope != null); + return (CompilationUnitScope) lastScope; + } + + public ArrayBinding createArray(TypeBinding type, int dimension) { + if (!type.isValidBinding()) + return new ArrayBinding(type, dimension); + return environment().createArrayType(type, dimension); + } + + public final ClassScope enclosingClassScope() { + Scope scope = this; + while ((scope = scope.parent) != null) { + if (scope instanceof ClassScope) return (ClassScope)scope; + } + return null; // may answer null if no type around + } + + public final MethodScope enclosingMethodScope() { + Scope scope = this; + while ((scope = scope.parent) != null) { + if (scope instanceof MethodScope) return (MethodScope)scope; + } + return null; // may answer null if no method around + } + + /* Answer the receiver's enclosing source type. + */ + public final SourceTypeBinding enclosingSourceType() { + Scope scope = this; + do { + if (scope instanceof ClassScope) + return ((ClassScope) scope).referenceContext.binding; + scope = scope.parent; + } while (scope != null); + return null; + } + public final LookupEnvironment environment() { + Scope scope, unitScope = this; + while ((scope = unitScope.parent) != null) + unitScope = scope; + return ((CompilationUnitScope) unitScope).environment; + } + + protected void faultInReceiverType(TypeBinding type) { + if (type.isArrayType()) + type = ((ArrayBinding) type).leafComponentType; + + // check on Begin bit, so as to be resilient with potential illformed binaries containing cycles (67769) + if (type instanceof BinaryTypeBinding && (type.tagBits & BeginHierarchyCheck) == 0) { + type.tagBits |= BeginHierarchyCheck; + // fault in the hierarchy of the type now so we can detect missing types instead of in storeDependencyInfo + BinaryTypeBinding binaryType = (BinaryTypeBinding) type; + ReferenceBinding enclosingType = binaryType.enclosingType(); + if (enclosingType != null) + faultInReceiverType(enclosingType); + ReferenceBinding superclass = binaryType.superclass(); + if (superclass != null) + faultInReceiverType(superclass); + ReferenceBinding[] interfaces = binaryType.superInterfaces(); + for (int i = 0, l = interfaces.length; i < l; i++) + faultInReceiverType(interfaces[i]); + type.tagBits |= EndHierarchyCheck; + } + } + + // abstract method lookup lookup (since maybe missing default abstract methods) + public MethodBinding findDefaultAbstractMethod( + ReferenceBinding receiverType, + char[] selector, + TypeBinding[] argumentTypes, + InvocationSite invocationSite, + ReferenceBinding classHierarchyStart, + MethodBinding matchingMethod, + ObjectVector found) { + + int startFoundSize = found.size; + ReferenceBinding currentType = classHierarchyStart; + while (currentType != null) { + matchingMethod = findMethodInSuperInterfaces(currentType, selector, found, matchingMethod); + currentType = currentType.superclass(); + } + int foundSize = found.size; + if (foundSize == startFoundSize) { + if (matchingMethod != null) compilationUnitScope().recordTypeReferences(matchingMethod.thrownExceptions); + return matchingMethod; // maybe null + } + MethodBinding[] candidates = new MethodBinding[foundSize - startFoundSize]; + int candidatesCount = 0; + // argument type compatibility check + for (int i = startFoundSize; i < foundSize; i++) { + MethodBinding methodBinding = (MethodBinding) found.elementAt(i); + if (areParametersAssignable(methodBinding.parameters, argumentTypes)) + candidates[candidatesCount++] = methodBinding; + } + if (candidatesCount == 1) { + compilationUnitScope().recordTypeReferences(candidates[0].thrownExceptions); + return candidates[0]; + } + if (candidatesCount == 0) { // try to find a close match when the parameter order is wrong or missing some parameters + int argLength = argumentTypes.length; + nextMethod : for (int i = 0; i < foundSize; i++) { + MethodBinding methodBinding = (MethodBinding) found.elementAt(i); + TypeBinding[] params = methodBinding.parameters; + int paramLength = params.length; + nextArg: for (int a = 0; a < argLength; a++) { + TypeBinding arg = argumentTypes[a]; + for (int p = 0; p < paramLength; p++) + if (params[p] == arg) + continue nextArg; + continue nextMethod; + } + return methodBinding; + } + return (MethodBinding) found.elementAt(0); // no good match so just use the first one found + } + // no need to check for visibility - interface methods are public + return mostSpecificInterfaceMethodBinding(candidates, candidatesCount); + } + + // Internal use only + public ReferenceBinding findDirectMemberType(char[] typeName, ReferenceBinding enclosingType) { + if ((enclosingType.tagBits & HasNoMemberTypes) != 0) + return null; // know it has no member types (nor inherited member types) + + SourceTypeBinding enclosingSourceType = enclosingSourceType(); + compilationUnitScope().recordReference(enclosingType.compoundName, typeName); + ReferenceBinding memberType = enclosingType.getMemberType(typeName); + if (memberType != null) { + compilationUnitScope().recordTypeReference(memberType); // to record supertypes + if (enclosingSourceType == null + ? memberType.canBeSeenBy(getCurrentPackage()) + : memberType.canBeSeenBy(enclosingType, enclosingSourceType)) + return memberType; + return new ProblemReferenceBinding(typeName, memberType, NotVisible); + } + return null; + } + + // Internal use only + public MethodBinding findExactMethod( + ReferenceBinding receiverType, + char[] selector, + TypeBinding[] argumentTypes, + InvocationSite invocationSite) { + + faultInReceiverType(receiverType); + compilationUnitScope().recordTypeReference(receiverType); + compilationUnitScope().recordTypeReferences(argumentTypes); + MethodBinding exactMethod = receiverType.getExactMethod(selector, argumentTypes); + if (exactMethod != null) { + compilationUnitScope().recordTypeReferences(exactMethod.thrownExceptions); + if (receiverType.isInterface() || exactMethod.canBeSeenBy(receiverType, invocationSite, this)) + return exactMethod; + } + return null; + } + + // Internal use only + /* Answer the field binding that corresponds to fieldName. + Start the lookup at the receiverType. + InvocationSite implements + isSuperAccess(); this is used to determine if the discovered field is visible. + Only fields defined by the receiverType or its supertypes are answered; + a field of an enclosing type will not be found using this API. + + If no visible field is discovered, null is answered. + */ + public FieldBinding findField(TypeBinding receiverType, char[] fieldName, InvocationSite invocationSite, boolean needResolve) { + if (receiverType.isBaseType()) return null; + if (receiverType.isArrayType()) { + TypeBinding leafType = receiverType.leafComponentType(); + if (leafType instanceof ReferenceBinding) { + if (!((ReferenceBinding) leafType).canBeSeenBy(this)) + return new ProblemFieldBinding((ReferenceBinding)leafType, fieldName, ReceiverTypeNotVisible); + } + if (CharOperation.equals(fieldName, LENGTH)) + return ArrayBinding.ArrayLength; + return null; + } + + faultInReceiverType(receiverType); + compilationUnitScope().recordTypeReference(receiverType); + + ReferenceBinding currentType = (ReferenceBinding) receiverType; + if (!currentType.canBeSeenBy(this)) + return new ProblemFieldBinding(currentType, fieldName, ReceiverTypeNotVisible); + + FieldBinding field = currentType.getField(fieldName, true /*resolve*/); + if (field != null) { + if (field.canBeSeenBy(currentType, invocationSite, this)) + return field; + return new ProblemFieldBinding(field /* closest match*/, field.declaringClass, fieldName, NotVisible); + } + // collect all superinterfaces of receiverType until the field is found in a supertype + ReferenceBinding[][] interfacesToVisit = null; + int lastPosition = -1; + FieldBinding visibleField = null; + boolean keepLooking = true; + boolean notVisible = false; + // we could hold onto the not visible field for extra error reporting + while (keepLooking) { + ReferenceBinding[] itsInterfaces = currentType.superInterfaces(); + if (itsInterfaces != NoSuperInterfaces) { + if (interfacesToVisit == null) + interfacesToVisit = new ReferenceBinding[5][]; + if (++lastPosition == interfacesToVisit.length) + System.arraycopy( + interfacesToVisit, + 0, + interfacesToVisit = new ReferenceBinding[lastPosition * 2][], + 0, + lastPosition); + interfacesToVisit[lastPosition] = itsInterfaces; + } + if ((currentType = currentType.superclass()) == null) + break; + + if ((field = currentType.getField(fieldName, needResolve)) != null) { + keepLooking = false; + if (field.canBeSeenBy(receiverType, invocationSite, this)) { + if (visibleField == null) + visibleField = field; + else + return new ProblemFieldBinding(visibleField /* closest match*/, visibleField.declaringClass, fieldName, Ambiguous); + } else { + notVisible = true; + } + } + } + + // walk all visible interfaces to find ambiguous references + if (interfacesToVisit != null) { + ProblemFieldBinding ambiguous = null; + done : for (int i = 0; i <= lastPosition; i++) { + ReferenceBinding[] interfaces = interfacesToVisit[i]; + for (int j = 0, length = interfaces.length; j < length; j++) { + ReferenceBinding anInterface = interfaces[j]; + if ((anInterface.tagBits & InterfaceVisited) == 0) { + // if interface as not already been visited + anInterface.tagBits |= InterfaceVisited; + if ((field = anInterface.getField(fieldName, true /*resolve*/)) != null) { + if (visibleField == null) { + visibleField = field; + } else { + ambiguous = new ProblemFieldBinding(visibleField /* closest match*/, visibleField.declaringClass, fieldName, Ambiguous); + break done; + } + } else { + ReferenceBinding[] itsInterfaces = anInterface.superInterfaces(); + if (itsInterfaces != NoSuperInterfaces) { + if (++lastPosition == interfacesToVisit.length) + System.arraycopy( + interfacesToVisit, + 0, + interfacesToVisit = new ReferenceBinding[lastPosition * 2][], + 0, + lastPosition); + interfacesToVisit[lastPosition] = itsInterfaces; + } + } + } + } + } + + // bit reinitialization + for (int i = 0; i <= lastPosition; i++) { + ReferenceBinding[] interfaces = interfacesToVisit[i]; + for (int j = 0, length = interfaces.length; j < length; j++) + interfaces[j].tagBits &= ~InterfaceVisited; + } + if (ambiguous != null) + return ambiguous; + } + + if (visibleField != null) + return visibleField; + if (notVisible) + return new ProblemFieldBinding(currentType, fieldName, NotVisible); + return null; + } + + // Internal use only + public ReferenceBinding findMemberType(char[] typeName, ReferenceBinding enclosingType) { + if ((enclosingType.tagBits & HasNoMemberTypes) != 0) + return null; // know it has no member types (nor inherited member types) + + SourceTypeBinding enclosingSourceType = enclosingSourceType(); + PackageBinding currentPackage = getCurrentPackage(); + compilationUnitScope().recordReference(enclosingType.compoundName, typeName); + ReferenceBinding memberType = enclosingType.getMemberType(typeName); + if (memberType != null) { + compilationUnitScope().recordTypeReference(memberType); // to record supertypes + if (enclosingSourceType == null + ? memberType.canBeSeenBy(currentPackage) + : memberType.canBeSeenBy(enclosingType, enclosingSourceType)) + return memberType; + return new ProblemReferenceBinding(typeName, memberType, NotVisible); + } + + // collect all superinterfaces of receiverType until the memberType is found in a supertype + ReferenceBinding currentType = enclosingType; + ReferenceBinding[][] interfacesToVisit = null; + int lastPosition = -1; + ReferenceBinding visibleMemberType = null; + boolean keepLooking = true; + ReferenceBinding notVisible = null; + // we could hold onto the not visible field for extra error reporting + while (keepLooking) { + ReferenceBinding[] itsInterfaces = currentType.superInterfaces(); + if (itsInterfaces != NoSuperInterfaces) { + if (interfacesToVisit == null) + interfacesToVisit = new ReferenceBinding[5][]; + if (++lastPosition == interfacesToVisit.length) + System.arraycopy( + interfacesToVisit, + 0, + interfacesToVisit = new ReferenceBinding[lastPosition * 2][], + 0, + lastPosition); + interfacesToVisit[lastPosition] = itsInterfaces; + } + if ((currentType = currentType.superclass()) == null) + break; + + compilationUnitScope().recordReference(currentType.compoundName, typeName); + if ((memberType = currentType.getMemberType(typeName)) != null) { + compilationUnitScope().recordTypeReference(memberType); // to record supertypes + keepLooking = false; + if (enclosingSourceType == null + ? memberType.canBeSeenBy(currentPackage) + : memberType.canBeSeenBy(enclosingType, enclosingSourceType)) { + if (visibleMemberType == null) + visibleMemberType = memberType; + else + return new ProblemReferenceBinding(typeName, Ambiguous); + } else { + notVisible = memberType; + } + } + } + // walk all visible interfaces to find ambiguous references + if (interfacesToVisit != null) { + ProblemReferenceBinding ambiguous = null; + done : for (int i = 0; i <= lastPosition; i++) { + ReferenceBinding[] interfaces = interfacesToVisit[i]; + for (int j = 0, length = interfaces.length; j < length; j++) { + ReferenceBinding anInterface = interfaces[j]; + if ((anInterface.tagBits & InterfaceVisited) == 0) { + // if interface as not already been visited + anInterface.tagBits |= InterfaceVisited; + compilationUnitScope().recordReference(anInterface.compoundName, typeName); + if ((memberType = anInterface.getMemberType(typeName)) != null) { + compilationUnitScope().recordTypeReference(memberType); // to record supertypes + if (visibleMemberType == null) { + visibleMemberType = memberType; + } else { + ambiguous = new ProblemReferenceBinding(typeName, Ambiguous); + break done; + } + } else { + ReferenceBinding[] itsInterfaces = anInterface.superInterfaces(); + if (itsInterfaces != NoSuperInterfaces) { + if (++lastPosition == interfacesToVisit.length) + System.arraycopy( + interfacesToVisit, + 0, + interfacesToVisit = new ReferenceBinding[lastPosition * 2][], + 0, + lastPosition); + interfacesToVisit[lastPosition] = itsInterfaces; + } + } + } + } + } + + // bit reinitialization + for (int i = 0; i <= lastPosition; i++) { + ReferenceBinding[] interfaces = interfacesToVisit[i]; + for (int j = 0, length = interfaces.length; j < length; j++) + interfaces[j].tagBits &= ~InterfaceVisited; + } + if (ambiguous != null) + return ambiguous; + } + if (visibleMemberType != null) + return visibleMemberType; + if (notVisible != null) + return new ProblemReferenceBinding(typeName, notVisible, NotVisible); + return null; + } + + // Internal use only + public MethodBinding findMethod( + ReferenceBinding receiverType, + char[] selector, + TypeBinding[] argumentTypes, + InvocationSite invocationSite) { + + ReferenceBinding currentType = receiverType; + MethodBinding matchingMethod = null; + ObjectVector found = new ObjectVector(); //TODO should rewrite to remove #matchingMethod since found is allocated anyway + + faultInReceiverType(receiverType); + compilationUnitScope().recordTypeReference(receiverType); + compilationUnitScope().recordTypeReferences(argumentTypes); + + if (currentType.isInterface()) { + MethodBinding[] currentMethods = currentType.getMethods(selector); + int currentLength = currentMethods.length; + if (currentLength == 1) { + matchingMethod = currentMethods[0]; + } else if (currentLength > 1) { + found.addAll(currentMethods); + } + matchingMethod = findMethodInSuperInterfaces(currentType, selector, found, matchingMethod); + currentType = getJavaLangObject(); + } + + boolean isCompliant14 = compilationUnitScope().environment.options.complianceLevel >= ClassFileConstants.JDK1_4; + // superclass lookup + ReferenceBinding classHierarchyStart = currentType; + while (currentType != null) { + MethodBinding[] currentMethods = currentType.getMethods(selector); + int currentLength = currentMethods.length; + + /* + * if 1.4 compliant, must filter out redundant protected methods from superclasses + */ + if (isCompliant14){ + nextMethod: for (int i = 0; i < currentLength; i++){ + MethodBinding currentMethod = currentMethods[i]; + // protected method need to be checked only - default access is already dealt with in #canBeSeen implementation + // when checking that p.C -> q.B -> p.A cannot see default access members from A through B. + if ((currentMethod.modifiers & AccProtected) == 0) continue nextMethod; + if (matchingMethod != null){ + if (currentMethod.areParametersEqual(matchingMethod)){ + currentLength--; + currentMethods[i] = null; // discard this match + continue nextMethod; + } + } else { + for (int j = 0, max = found.size; j < max; j++) { + if (((MethodBinding)found.elementAt(j)).areParametersEqual(currentMethod)){ + currentLength--; + currentMethods[i] = null; + continue nextMethod; + } + } + } + } + } + + if (currentLength == 1 && matchingMethod == null && found.size == 0) { + matchingMethod = currentMethods[0]; + } else if (currentLength > 0) { + if (matchingMethod != null) { + found.add(matchingMethod); + matchingMethod = null; + } + // append currentMethods, filtering out null entries + int maxMethod = currentMethods.length; + if (maxMethod == currentLength) { // no method was eliminated for 1.4 compliance (see above) + found.addAll(currentMethods); + } else { + for (int i = 0, max = currentMethods.length; i < max; i++) { + MethodBinding currentMethod = currentMethods[i]; + if (currentMethod != null) found.add(currentMethod); + } + } + } + currentType = currentType.superclass(); + } + + // if found several candidates, then eliminate those not matching argument types + int foundSize = found.size; + MethodBinding[] candidates = null; + int candidatesCount = 0; + boolean checkedMatchingMethod = false; // is matchingMethod meeting argument expectation ? + if (foundSize > 0) { + // argument type compatibility check + for (int i = 0; i < foundSize; i++) { + MethodBinding methodBinding = (MethodBinding) found.elementAt(i); + if (areParametersAssignable(methodBinding.parameters, argumentTypes)) { + switch (candidatesCount) { + case 0: + matchingMethod = methodBinding; // if only one match, reuse matchingMethod + checkedMatchingMethod = true; // matchingMethod is known to exist and match params here + break; + case 1: + candidates = new MethodBinding[foundSize]; // only lazily created if more than one match + candidates[0] = matchingMethod; // copy back + matchingMethod = null; + // fall through + default: + candidates[candidatesCount] = methodBinding; + } + candidatesCount++; + } + } + } + // if only one matching method left (either from start or due to elimination of rivals), then match is in matchingMethod + if (matchingMethod != null) { + if (checkedMatchingMethod || areParametersAssignable(matchingMethod.parameters, argumentTypes)) { + // (if no default abstract) must explicitly look for one instead, which could be a better match + if (!matchingMethod.canBeSeenBy(receiverType, invocationSite, this)) { + // ignore matching method (to be consistent with multiple matches, none visible (matching method is then null) + MethodBinding interfaceMethod = findDefaultAbstractMethod(receiverType, selector, argumentTypes, invocationSite, classHierarchyStart, null, found); + if (interfaceMethod != null) return interfaceMethod; + compilationUnitScope().recordTypeReferences(matchingMethod.thrownExceptions); + return matchingMethod; + } + } + return findDefaultAbstractMethod(receiverType, selector, argumentTypes, invocationSite, classHierarchyStart, matchingMethod, found); + } + + // no match was found, try to find a close match when the parameter order is wrong or missing some parameters + if (candidatesCount == 0) { + MethodBinding interfaceMethod = + findDefaultAbstractMethod(receiverType, selector, argumentTypes, invocationSite, classHierarchyStart, matchingMethod, found); + if (interfaceMethod != null) return interfaceMethod; + + int argLength = argumentTypes.length; + foundSize = found.size; + nextMethod : for (int i = 0; i < foundSize; i++) { + MethodBinding methodBinding = (MethodBinding) found.elementAt(i); + TypeBinding[] params = methodBinding.parameters; + int paramLength = params.length; + nextArg: for (int a = 0; a < argLength; a++) { + TypeBinding arg = argumentTypes[a]; + for (int p = 0; p < paramLength; p++) + if (params[p] == arg) + continue nextArg; + continue nextMethod; + } + return methodBinding; + } + return (MethodBinding) found.elementAt(0); // no good match so just use the first one found + } + + // tiebreak using visibility check + int visiblesCount = 0; + for (int i = 0; i < candidatesCount; i++) { + MethodBinding methodBinding = candidates[i]; + if (methodBinding.canBeSeenBy(receiverType, invocationSite, this)) { + if (visiblesCount != i) { + candidates[i] = null; + candidates[visiblesCount] = methodBinding; + } + visiblesCount++; + } + } + if (visiblesCount == 1) { + compilationUnitScope().recordTypeReferences(candidates[0].thrownExceptions); + return candidates[0]; + } + if (visiblesCount == 0) { + MethodBinding interfaceMethod = + findDefaultAbstractMethod(receiverType, selector, argumentTypes, invocationSite, classHierarchyStart, matchingMethod, found); + if (interfaceMethod != null) return interfaceMethod; + return new ProblemMethodBinding(candidates[0], candidates[0].selector, candidates[0].parameters, NotVisible); + } + if (isCompliant14) + return mostSpecificMethodBinding(candidates, visiblesCount); + return candidates[0].declaringClass.isClass() + ? mostSpecificClassMethodBinding(candidates, visiblesCount) + : mostSpecificInterfaceMethodBinding(candidates, visiblesCount); + } + + // Internal use only + public MethodBinding findMethodForArray( + ArrayBinding receiverType, + char[] selector, + TypeBinding[] argumentTypes, + InvocationSite invocationSite) { + + TypeBinding leafType = receiverType.leafComponentType(); + if (leafType instanceof ReferenceBinding) { + if (!((ReferenceBinding) leafType).canBeSeenBy(this)) + return new ProblemMethodBinding(selector, TypeConstants.NoParameters, (ReferenceBinding)leafType, ReceiverTypeNotVisible); + } + + ReferenceBinding object = getJavaLangObject(); + MethodBinding methodBinding = object.getExactMethod(selector, argumentTypes); + if (methodBinding != null) { + // handle the method clone() specially... cannot be protected or throw exceptions + if (argumentTypes == NoParameters && CharOperation.equals(selector, CLONE)) + return new UpdatedMethodBinding( + environment().options.targetJDK >= ClassFileConstants.JDK1_4 ? (TypeBinding)receiverType : (TypeBinding)object, // remember its array type for codegen purpose on target>=1.4.0 + (methodBinding.modifiers ^ AccProtected) | AccPublic, + CLONE, + methodBinding.returnType, + argumentTypes, + null, + object); + if (methodBinding.canBeSeenBy(receiverType, invocationSite, this)) + return methodBinding; + } + // answers closest approximation, may not check argumentTypes or visibility + methodBinding = findMethod(object, selector, argumentTypes, invocationSite); + if (methodBinding == null) + return new ProblemMethodBinding(selector, argumentTypes, NotFound); + if (methodBinding.isValidBinding()) { + if (!areParametersAssignable(methodBinding.parameters, argumentTypes)) + return new ProblemMethodBinding( + methodBinding, + selector, + argumentTypes, + NotFound); + if (!methodBinding.canBeSeenBy(receiverType, invocationSite, this)) + return new ProblemMethodBinding( + methodBinding, + selector, + methodBinding.parameters, + NotVisible); + } + return methodBinding; + } + + public MethodBinding findMethodInSuperInterfaces( + ReferenceBinding currentType, + char[] selector, + ObjectVector found, + MethodBinding matchingMethod) { + + ReferenceBinding[] itsInterfaces = currentType.superInterfaces(); + if (itsInterfaces != NoSuperInterfaces) { + ReferenceBinding[][] interfacesToVisit = new ReferenceBinding[5][]; + int lastPosition = -1; + if (++lastPosition == interfacesToVisit.length) + System.arraycopy( + interfacesToVisit, 0, + interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, + lastPosition); + interfacesToVisit[lastPosition] = itsInterfaces; + + for (int i = 0; i <= lastPosition; i++) { + ReferenceBinding[] interfaces = interfacesToVisit[i]; + for (int j = 0, length = interfaces.length; j < length; j++) { + currentType = interfaces[j]; + if ((currentType.tagBits & InterfaceVisited) == 0) { + // if interface as not already been visited + currentType.tagBits |= InterfaceVisited; + + MethodBinding[] currentMethods = currentType.getMethods(selector); + int currentLength = currentMethods.length; + if (currentLength == 1 && matchingMethod == null && found.size == 0) { + matchingMethod = currentMethods[0]; + } else if (currentLength > 0) { + if (matchingMethod != null) { + found.add(matchingMethod); + matchingMethod = null; + } + found.addAll(currentMethods); + } + itsInterfaces = currentType.superInterfaces(); + if (itsInterfaces != NoSuperInterfaces) { + if (++lastPosition == interfacesToVisit.length) + System.arraycopy( + interfacesToVisit, 0, + interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, + lastPosition); + interfacesToVisit[lastPosition] = itsInterfaces; + } + } + } + } + + // bit reinitialization + for (int i = 0; i <= lastPosition; i++) { + ReferenceBinding[] interfaces = interfacesToVisit[i]; + for (int j = 0, length = interfaces.length; j < length; j++) + interfaces[j].tagBits &= ~InterfaceVisited; + } + } + return matchingMethod; + } + + // Internal use only + public ReferenceBinding findType( + char[] typeName, + PackageBinding declarationPackage, + PackageBinding invocationPackage) { + + compilationUnitScope().recordReference(declarationPackage.compoundName, typeName); + ReferenceBinding typeBinding = declarationPackage.getType(typeName); + if (typeBinding == null) + return null; + + if (typeBinding.isValidBinding()) { + if (declarationPackage != invocationPackage && !typeBinding.canBeSeenBy(invocationPackage)) + return new ProblemReferenceBinding(typeName, typeBinding, NotVisible); + } + return typeBinding; + } + + public LocalVariableBinding findVariable(char[] variable) { + + return null; + } + + public TypeBinding getBaseType(char[] name) { + // list should be optimized (with most often used first) + int length = name.length; + if (length > 2 && length < 8) { + switch (name[0]) { + case 'i' : + if (length == 3 && name[1] == 'n' && name[2] == 't') + return IntBinding; + break; + case 'v' : + if (length == 4 && name[1] == 'o' && name[2] == 'i' && name[3] == 'd') + return VoidBinding; + break; + case 'b' : + if (length == 7 + && name[1] == 'o' + && name[2] == 'o' + && name[3] == 'l' + && name[4] == 'e' + && name[5] == 'a' + && name[6] == 'n') + return BooleanBinding; + if (length == 4 && name[1] == 'y' && name[2] == 't' && name[3] == 'e') + return ByteBinding; + break; + case 'c' : + if (length == 4 && name[1] == 'h' && name[2] == 'a' && name[3] == 'r') + return CharBinding; + break; + case 'd' : + if (length == 6 + && name[1] == 'o' + && name[2] == 'u' + && name[3] == 'b' + && name[4] == 'l' + && name[5] == 'e') + return DoubleBinding; + break; + case 'f' : + if (length == 5 + && name[1] == 'l' + && name[2] == 'o' + && name[3] == 'a' + && name[4] == 't') + return FloatBinding; + break; + case 'l' : + if (length == 4 && name[1] == 'o' && name[2] == 'n' && name[3] == 'g') + return LongBinding; + break; + case 's' : + if (length == 5 + && name[1] == 'h' + && name[2] == 'o' + && name[3] == 'r' + && name[4] == 't') + return ShortBinding; + } + } + return null; + } + + /* API + * + * Answer the binding that corresponds to the argument name. + * flag is a mask of the following values VARIABLE (= FIELD or LOCAL), TYPE, PACKAGE. + * Only bindings corresponding to the mask can be answered. + * + * For example, getBinding("foo", VARIABLE, site) will answer + * the binding for the field or local named "foo" (or an error binding if none exists). + * If a type named "foo" exists, it will not be detected (and an error binding will be answered) + * + * The VARIABLE mask has precedence over the TYPE mask. + * + * If the VARIABLE mask is not set, neither fields nor locals will be looked for. + * + * InvocationSite implements: + * isSuperAccess(); this is used to determine if the discovered field is visible. + * + * Limitations: cannot request FIELD independently of LOCAL, or vice versa + */ + public Binding getBinding(char[] name, int mask, InvocationSite invocationSite, boolean needResolve) { + + try { + Binding binding = null; + FieldBinding problemField = null; + if ((mask & VARIABLE) != 0) { + boolean insideStaticContext = false; + boolean insideConstructorCall = false; + + FieldBinding foundField = null; + // can be a problem field which is answered if a valid field is not found + ProblemFieldBinding foundInsideProblem = null; + // inside Constructor call or inside static context + Scope scope = this; + int depth = 0; + int foundDepth = 0; + ReferenceBinding foundActualReceiverType = null; + done : while (true) { // done when a COMPILATION_UNIT_SCOPE is found + switch (scope.kind) { + case METHOD_SCOPE : + MethodScope methodScope = (MethodScope) scope; + insideStaticContext |= methodScope.isStatic; + insideConstructorCall |= methodScope.isConstructorCall; + // Fall through... could duplicate the code below to save a cast - questionable optimization + case BLOCK_SCOPE : + LocalVariableBinding variableBinding = scope.findVariable(name); + // looks in this scope only + if (variableBinding != null) { + if (foundField != null && foundField.isValidBinding()) + return new ProblemFieldBinding( + foundField, // closest match + foundField.declaringClass, + name, + InheritedNameHidesEnclosingName); + if (depth > 0) + invocationSite.setDepth(depth); + return variableBinding; + } + break; + case CLASS_SCOPE : + ClassScope classScope = (ClassScope) scope; + SourceTypeBinding enclosingType = classScope.referenceContext.binding; + FieldBinding fieldBinding = + classScope.findField(enclosingType, name, invocationSite, needResolve); + // Use next line instead if willing to enable protected access accross inner types + // FieldBinding fieldBinding = findField(enclosingType, name, invocationSite); + if (fieldBinding != null) { // skip it if we did not find anything + if (fieldBinding.problemId() == Ambiguous) { + if (foundField == null || foundField.problemId() == NotVisible) + // supercedes any potential InheritedNameHidesEnclosingName problem + return fieldBinding; + // make the user qualify the field, likely wants the first inherited field (javac generates an ambiguous error instead) + return new ProblemFieldBinding( + foundField, // closest match + foundField.declaringClass, + name, + InheritedNameHidesEnclosingName); + } + + ProblemFieldBinding insideProblem = null; + if (fieldBinding.isValidBinding()) { + if (!fieldBinding.isStatic()) { + if (insideConstructorCall) { + insideProblem = + new ProblemFieldBinding( + fieldBinding, // closest match + fieldBinding.declaringClass, + name, + NonStaticReferenceInConstructorInvocation); + } else if (insideStaticContext) { + insideProblem = + new ProblemFieldBinding( + fieldBinding, // closest match + fieldBinding.declaringClass, + name, + NonStaticReferenceInStaticContext); + } + } + if (enclosingType == fieldBinding.declaringClass + || environment().options.complianceLevel >= ClassFileConstants.JDK1_4){ + // found a valid field in the 'immediate' scope (ie. not inherited) + // OR in 1.4 mode (inherited shadows enclosing) + if (foundField == null) { + if (depth > 0){ + invocationSite.setDepth(depth); + invocationSite.setActualReceiverType(enclosingType); + } + // return the fieldBinding if it is not declared in a superclass of the scope's binding (that is, inherited) + return insideProblem == null ? fieldBinding : insideProblem; + } + if (foundField.isValidBinding()) + // if a valid field was found, complain when another is found in an 'immediate' enclosing type (that is, not inherited) + if (foundField.declaringClass != fieldBinding.declaringClass) + // ie. have we found the same field - do not trust field identity yet + return new ProblemFieldBinding( + foundField, // closest match + foundField.declaringClass, + name, + InheritedNameHidesEnclosingName); + } + } + + if (foundField == null + || (foundField.problemId() == NotVisible + && fieldBinding.problemId() != NotVisible)) { + // only remember the fieldBinding if its the first one found or the previous one was not visible & fieldBinding is... + foundDepth = depth; + foundActualReceiverType = enclosingType; + foundInsideProblem = insideProblem; + foundField = fieldBinding; + } + } + depth++; + insideStaticContext |= enclosingType.isStatic(); + // 1EX5I8Z - accessing outer fields within a constructor call is permitted + // in order to do so, we change the flag as we exit from the type, not the method + // itself, because the class scope is used to retrieve the fields. + MethodScope enclosingMethodScope = scope.methodScope(); + insideConstructorCall = + enclosingMethodScope == null ? false : enclosingMethodScope.isConstructorCall; + break; + case COMPILATION_UNIT_SCOPE : + break done; + } + scope = scope.parent; + } + + if (foundInsideProblem != null) + return foundInsideProblem; + if (foundField != null) { + if (foundField.isValidBinding()){ + if (foundDepth > 0){ + invocationSite.setDepth(foundDepth); + invocationSite.setActualReceiverType(foundActualReceiverType); + } + return foundField; + } + problemField = foundField; + } + } + + // We did not find a local or instance variable. + if ((mask & TYPE) != 0) { + if ((binding = getBaseType(name)) != null) + return binding; + binding = getTypeOrPackage(name, (mask & PACKAGE) == 0 ? TYPE : TYPE | PACKAGE); + if (binding.isValidBinding() || mask == TYPE) + return binding; + // answer the problem type binding if we are only looking for a type + } else if ((mask & PACKAGE) != 0) { + compilationUnitScope().recordSimpleReference(name); + if ((binding = environment().getTopLevelPackage(name)) != null) + return binding; + } + if (problemField != null) return problemField; + return new ProblemBinding(name, enclosingSourceType(), NotFound); + + } catch (AbortCompilation e) { + e.updateContext(invocationSite, referenceCompilationUnit().compilationResult); + throw e; + } + } + + public MethodBinding getConstructor(ReferenceBinding receiverType, TypeBinding[] argumentTypes, InvocationSite invocationSite) { + try { + faultInReceiverType(receiverType); + compilationUnitScope().recordTypeReference(receiverType); + compilationUnitScope().recordTypeReferences(argumentTypes); + MethodBinding methodBinding = receiverType.getExactConstructor(argumentTypes); + if (methodBinding != null && methodBinding.canBeSeenBy(invocationSite, this)) + return methodBinding; + MethodBinding[] methods = receiverType.getMethods(ConstructorDeclaration.ConstantPoolName); + if (methods == NoMethods) + return new ProblemMethodBinding( + ConstructorDeclaration.ConstantPoolName, + argumentTypes, + NotFound); + + MethodBinding[] compatible = new MethodBinding[methods.length]; + int compatibleIndex = 0; + for (int i = 0, length = methods.length; i < length; i++) + if (areParametersAssignable(methods[i].parameters, argumentTypes)) + compatible[compatibleIndex++] = methods[i]; + if (compatibleIndex == 0) + return new ProblemMethodBinding( + ConstructorDeclaration.ConstantPoolName, + argumentTypes, + NotFound); + // need a more descriptive error... cannot convert from X to Y + + MethodBinding[] visible = new MethodBinding[compatibleIndex]; + int visibleIndex = 0; + for (int i = 0; i < compatibleIndex; i++) { + MethodBinding method = compatible[i]; + if (method.canBeSeenBy(invocationSite, this)) + visible[visibleIndex++] = method; + } + if (visibleIndex == 1) return visible[0]; + if (visibleIndex == 0) + return new ProblemMethodBinding( + compatible[0], + ConstructorDeclaration.ConstantPoolName, + compatible[0].parameters, + NotVisible); + return mostSpecificClassMethodBinding(visible, visibleIndex); + } catch (AbortCompilation e) { + e.updateContext(invocationSite, referenceCompilationUnit().compilationResult); + throw e; + } + } + + public final PackageBinding getCurrentPackage() { + Scope scope, unitScope = this; + while ((scope = unitScope.parent) != null) + unitScope = scope; + return ((CompilationUnitScope) unitScope).fPackage; + } + + /** + * Returns the modifiers of the innermost enclosing declaration. + * @return modifiers + */ + public int getDeclarationModifiers(){ + switch(this.kind){ + case Scope.BLOCK_SCOPE : + case Scope.METHOD_SCOPE : + MethodScope methodScope = methodScope(); + if (!methodScope.isInsideInitializer()){ + // check method modifiers to see if deprecated + MethodBinding context = ((AbstractMethodDeclaration)methodScope.referenceContext).binding; + if (context != null) { + return context.modifiers; + } + } else { + SourceTypeBinding type = ((BlockScope)this).referenceType().binding; + + // inside field declaration ? check field modifier to see if deprecated + if (methodScope.initializedField != null) { + return methodScope.initializedField.modifiers; + } + if (type != null) { + return type.modifiers; + } + } + break; + case Scope.CLASS_SCOPE : + ReferenceBinding context = ((ClassScope)this).referenceType().binding; + if (context != null) { + return context.modifiers; + } + break; + } + return -1; + } + + public FieldBinding getField(TypeBinding receiverType, char[] fieldName, InvocationSite invocationSite) { + try { + FieldBinding field = findField(receiverType, fieldName, invocationSite, true /*resolve*/); + if (field != null) return field; + + return new ProblemFieldBinding( + receiverType instanceof ReferenceBinding ? (ReferenceBinding) receiverType : null, + fieldName, + NotFound); + } catch (AbortCompilation e) { + e.updateContext(invocationSite, referenceCompilationUnit().compilationResult); + throw e; + } + } + + /* API + * + * Answer the method binding that corresponds to selector, argumentTypes. + * Start the lookup at the enclosing type of the receiver. + * InvocationSite implements + * isSuperAccess(); this is used to determine if the discovered method is visible. + * setDepth(int); this is used to record the depth of the discovered method + * relative to the enclosing type of the receiver. (If the method is defined + * in the enclosing type of the receiver, the depth is 0; in the next enclosing + * type, the depth is 1; and so on + * + * If no visible method is discovered, an error binding is answered. + */ + public MethodBinding getImplicitMethod( + char[] selector, + TypeBinding[] argumentTypes, + InvocationSite invocationSite) { + + boolean insideStaticContext = false; + boolean insideConstructorCall = false; + MethodBinding foundMethod = null; + ProblemMethodBinding foundFuzzyProblem = null; + // the weird method lookup case (matches method name in scope, then arg types, then visibility) + ProblemMethodBinding foundInsideProblem = null; + // inside Constructor call or inside static context + Scope scope = this; + int depth = 0; + done : while (true) { // done when a COMPILATION_UNIT_SCOPE is found + switch (scope.kind) { + case METHOD_SCOPE : + MethodScope methodScope = (MethodScope) scope; + insideStaticContext |= methodScope.isStatic; + insideConstructorCall |= methodScope.isConstructorCall; + break; + case CLASS_SCOPE : + ClassScope classScope = (ClassScope) scope; + SourceTypeBinding receiverType = classScope.referenceContext.binding; + boolean isExactMatch = true; + // retrieve an exact visible match (if possible) + MethodBinding methodBinding = + (foundMethod == null) + ? classScope.findExactMethod( + receiverType, + selector, + argumentTypes, + invocationSite) + : classScope.findExactMethod( + receiverType, + foundMethod.selector, + foundMethod.parameters, + invocationSite); + // ? findExactMethod(receiverType, selector, argumentTypes, invocationSite) + // : findExactMethod(receiverType, foundMethod.selector, foundMethod.parameters, invocationSite); + if (methodBinding == null) { + // answers closest approximation, may not check argumentTypes or visibility + isExactMatch = false; + methodBinding = + classScope.findMethod(receiverType, selector, argumentTypes, invocationSite); + // methodBinding = findMethod(receiverType, selector, argumentTypes, invocationSite); + } + if (methodBinding != null) { // skip it if we did not find anything + if (methodBinding.problemId() == Ambiguous) { + if (foundMethod == null || foundMethod.problemId() == NotVisible) { + // supercedes any potential InheritedNameHidesEnclosingName problem + return methodBinding; + } + // make the user qualify the method, likely wants the first inherited method (javac generates an ambiguous error instead) + return new ProblemMethodBinding( + methodBinding, // closest match + selector, + argumentTypes, + InheritedNameHidesEnclosingName); + } + ProblemMethodBinding fuzzyProblem = null; + ProblemMethodBinding insideProblem = null; + if (methodBinding.isValidBinding()) { + if (!isExactMatch) { + if (!areParametersAssignable(methodBinding.parameters, argumentTypes)) { + if (foundMethod == null || foundMethod.problemId() == NotVisible){ + // inherited mismatch is reported directly, not looking at enclosing matches + return new ProblemMethodBinding(methodBinding, selector, argumentTypes, NotFound); + } + // make the user qualify the method, likely wants the first inherited method (javac generates an ambiguous error instead) + fuzzyProblem = new ProblemMethodBinding(selector, methodBinding.parameters, InheritedNameHidesEnclosingName); + + } else if (!methodBinding.canBeSeenBy(receiverType, invocationSite, classScope)) { + // using instead of for visibility check does grant all access to innerclass + fuzzyProblem = + new ProblemMethodBinding( + methodBinding, + selector, + methodBinding.parameters, + NotVisible); + } + } + if (fuzzyProblem == null && !methodBinding.isStatic()) { + if (insideConstructorCall) { + insideProblem = + new ProblemMethodBinding( + methodBinding, // closest match + methodBinding.selector, + methodBinding.parameters, + NonStaticReferenceInConstructorInvocation); + } else if (insideStaticContext) { + insideProblem = + new ProblemMethodBinding( + methodBinding, // closest match + methodBinding.selector, + methodBinding.parameters, + NonStaticReferenceInStaticContext); + } + } + + if (receiverType == methodBinding.declaringClass + || (receiverType.getMethods(selector)) != NoMethods + || ((fuzzyProblem == null || fuzzyProblem.problemId() != NotVisible) && environment().options.complianceLevel >= ClassFileConstants.JDK1_4)){ + // found a valid method in the 'immediate' scope (ie. not inherited) + // OR the receiverType implemented a method with the correct name + // OR in 1.4 mode (inherited visible shadows enclosing) + if (foundMethod == null) { + if (depth > 0){ + invocationSite.setDepth(depth); + invocationSite.setActualReceiverType(receiverType); + } + // return the methodBinding if it is not declared in a superclass of the scope's binding (that is, inherited) + if (fuzzyProblem != null) + return fuzzyProblem; + if (insideProblem != null) + return insideProblem; + return methodBinding; + } + // if a method was found, complain when another is found in an 'immediate' enclosing type (that is, not inherited) + // NOTE: Unlike fields, a non visible method hides a visible method + if (foundMethod.declaringClass != methodBinding.declaringClass) + // ie. have we found the same method - do not trust field identity yet + return new ProblemMethodBinding( + methodBinding, // closest match + methodBinding.selector, + methodBinding.parameters, + InheritedNameHidesEnclosingName); + } + } + + if (foundMethod == null + || (foundMethod.problemId() == NotVisible + && methodBinding.problemId() != NotVisible)) { + // only remember the methodBinding if its the first one found or the previous one was not visible & methodBinding is... + // remember that private methods are visible if defined directly by an enclosing class + if (depth > 0){ + invocationSite.setDepth(depth); + invocationSite.setActualReceiverType(receiverType); + } + foundFuzzyProblem = fuzzyProblem; + foundInsideProblem = insideProblem; + if (fuzzyProblem == null) + foundMethod = methodBinding; // only keep it if no error was found + } + } + depth++; + insideStaticContext |= receiverType.isStatic(); + // 1EX5I8Z - accessing outer fields within a constructor call is permitted + // in order to do so, we change the flag as we exit from the type, not the method + // itself, because the class scope is used to retrieve the fields. + MethodScope enclosingMethodScope = scope.methodScope(); + insideConstructorCall = + enclosingMethodScope == null ? false : enclosingMethodScope.isConstructorCall; + break; + case COMPILATION_UNIT_SCOPE : + break done; + } + scope = scope.parent; + } + + if (foundFuzzyProblem != null) + return foundFuzzyProblem; + if (foundInsideProblem != null) + return foundInsideProblem; + if (foundMethod != null) + return foundMethod; + return new ProblemMethodBinding(selector, argumentTypes, NotFound); + } + + public final ReferenceBinding getJavaIoSerializable() { + compilationUnitScope().recordQualifiedReference(JAVA_IO_SERIALIZABLE); + ReferenceBinding type = environment().getType(JAVA_IO_SERIALIZABLE); + if (type != null) return type; + + problemReporter().isClassPathCorrect(JAVA_IO_SERIALIZABLE, referenceCompilationUnit()); + return null; // will not get here since the above error aborts the compilation + } + + public final ReferenceBinding getJavaLangAssertionError() { + compilationUnitScope().recordQualifiedReference(JAVA_LANG_ASSERTIONERROR); + ReferenceBinding type = environment().getType(JAVA_LANG_ASSERTIONERROR); + if (type != null) return type; + problemReporter().isClassPathCorrect(JAVA_LANG_ASSERTIONERROR, referenceCompilationUnit()); + return null; // will not get here since the above error aborts the compilation + } + + public final ReferenceBinding getJavaLangClass() { + compilationUnitScope().recordQualifiedReference(JAVA_LANG_CLASS); + ReferenceBinding type = environment().getType(JAVA_LANG_CLASS); + if (type != null) return type; + + problemReporter().isClassPathCorrect(JAVA_LANG_CLASS, referenceCompilationUnit()); + return null; // will not get here since the above error aborts the compilation + } + + public final ReferenceBinding getJavaLangCloneable() { + compilationUnitScope().recordQualifiedReference(JAVA_LANG_CLONEABLE); + ReferenceBinding type = environment().getType(JAVA_LANG_CLONEABLE); + if (type != null) return type; + + problemReporter().isClassPathCorrect(JAVA_LANG_CLONEABLE, referenceCompilationUnit()); + return null; // will not get here since the above error aborts the compilation + } + + public final ReferenceBinding getJavaLangError() { + compilationUnitScope().recordQualifiedReference(JAVA_LANG_ERROR); + ReferenceBinding type = environment().getType(JAVA_LANG_ERROR); + if (type != null) return type; + + problemReporter().isClassPathCorrect(JAVA_LANG_ERROR, referenceCompilationUnit()); + return null; // will not get here since the above error aborts the compilation + } + + public final ReferenceBinding getJavaLangObject() { + compilationUnitScope().recordQualifiedReference(JAVA_LANG_OBJECT); + ReferenceBinding type = environment().getType(JAVA_LANG_OBJECT); + if (type != null) return type; + + problemReporter().isClassPathCorrect(JAVA_LANG_OBJECT, referenceCompilationUnit()); + return null; // will not get here since the above error aborts the compilation + } + + public final ReferenceBinding getJavaLangRuntimeException() { + compilationUnitScope().recordQualifiedReference(JAVA_LANG_RUNTIMEEXCEPTION); + ReferenceBinding type = environment().getType(JAVA_LANG_RUNTIMEEXCEPTION); + if (type != null) return type; + + problemReporter().isClassPathCorrect(JAVA_LANG_RUNTIMEEXCEPTION, referenceCompilationUnit()); + return null; // will not get here since the above error aborts the compilation + } + + public final ReferenceBinding getJavaLangString() { + compilationUnitScope().recordQualifiedReference(JAVA_LANG_STRING); + ReferenceBinding type = environment().getType(JAVA_LANG_STRING); + if (type != null) return type; + + problemReporter().isClassPathCorrect(JAVA_LANG_STRING, referenceCompilationUnit()); + return null; // will not get here since the above error aborts the compilation + } + + public final ReferenceBinding getJavaLangThrowable() { + compilationUnitScope().recordQualifiedReference(JAVA_LANG_THROWABLE); + ReferenceBinding type = environment().getType(JAVA_LANG_THROWABLE); + if (type != null) return type; + + problemReporter().isClassPathCorrect(JAVA_LANG_THROWABLE, referenceCompilationUnit()); + return null; // will not get here since the above error aborts the compilation + } + + /* Answer the type binding corresponding to the typeName argument, relative to the enclosingType. + */ + public final ReferenceBinding getMemberType(char[] typeName, ReferenceBinding enclosingType) { + ReferenceBinding memberType = findMemberType(typeName, enclosingType); + if (memberType != null) return memberType; + return new ProblemReferenceBinding(typeName, NotFound); + } + + public MethodBinding getMethod(TypeBinding receiverType, char[] selector, TypeBinding[] argumentTypes, InvocationSite invocationSite) { + try { + if (receiverType.isArrayType()) + return findMethodForArray((ArrayBinding) receiverType, selector, argumentTypes, invocationSite); + if (receiverType.isBaseType()) + return new ProblemMethodBinding(selector, argumentTypes, NotFound); + + ReferenceBinding currentType = (ReferenceBinding) receiverType; + if (!currentType.canBeSeenBy(this)) + return new ProblemMethodBinding(selector, argumentTypes, ReceiverTypeNotVisible); + + // retrieve an exact visible match (if possible) + MethodBinding methodBinding = findExactMethod(currentType, selector, argumentTypes, invocationSite); + if (methodBinding != null) return methodBinding; + + // answers closest approximation, may not check argumentTypes or visibility + methodBinding = findMethod(currentType, selector, argumentTypes, invocationSite); + if (methodBinding == null) + return new ProblemMethodBinding(selector, argumentTypes, NotFound); + if (methodBinding.isValidBinding()) { + if (!areParametersAssignable(methodBinding.parameters, argumentTypes)) + return new ProblemMethodBinding( + methodBinding, + selector, + argumentTypes, + NotFound); + if (!methodBinding.canBeSeenBy(currentType, invocationSite, this)) + return new ProblemMethodBinding( + methodBinding, + selector, + methodBinding.parameters, + NotVisible); + } + return methodBinding; + + } catch (AbortCompilation e) { + e.updateContext(invocationSite, referenceCompilationUnit().compilationResult); + throw e; + } + } + + /* Answer the type binding that corresponds the given name, starting the lookup in the receiver. + * The name provided is a simple source name (e.g., "Object" , "Point", ...) + */ + // The return type of this method could be ReferenceBinding if we did not answer base types. + // NOTE: We could support looking for Base Types last in the search, however any code using + // this feature would be extraordinarily slow. Therefore we don't do this + public final TypeBinding getType(char[] name) { + // Would like to remove this test and require senders to specially handle base types + TypeBinding binding = getBaseType(name); + if (binding != null) return binding; + return (ReferenceBinding) getTypeOrPackage(name, TYPE); + } + + /* Answer the type binding corresponding to the compoundName. + * + * NOTE: If a problem binding is returned, senders should extract the compound name + * from the binding & not assume the problem applies to the entire compoundName. + */ + public final TypeBinding getType(char[][] compoundName) { + int typeNameLength = compoundName.length; + if (typeNameLength == 1) { + // Would like to remove this test and require senders to specially handle base types + TypeBinding binding = getBaseType(compoundName[0]); + if (binding != null) return binding; + } + + compilationUnitScope().recordQualifiedReference(compoundName); + Binding binding = + getTypeOrPackage(compoundName[0], typeNameLength == 1 ? TYPE : TYPE | PACKAGE); + if (binding == null) + return new ProblemReferenceBinding(compoundName[0], NotFound); + if (!binding.isValidBinding()) + return (ReferenceBinding) binding; + + int currentIndex = 1; + boolean checkVisibility = false; + if (binding instanceof PackageBinding) { + PackageBinding packageBinding = (PackageBinding) binding; + while (currentIndex < typeNameLength) { + binding = packageBinding.getTypeOrPackage(compoundName[currentIndex++]); // does not check visibility + if (binding == null) + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + NotFound); + if (!binding.isValidBinding()) + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + binding.problemId()); + if (!(binding instanceof PackageBinding)) + break; + packageBinding = (PackageBinding) binding; + } + if (binding instanceof PackageBinding) + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + NotFound); + checkVisibility = true; + } + + // binding is now a ReferenceBinding + ReferenceBinding typeBinding = (ReferenceBinding) binding; + compilationUnitScope().recordTypeReference(typeBinding); // to record supertypes + if (checkVisibility) // handles the fall through case + if (!typeBinding.canBeSeenBy(this)) + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + typeBinding, + NotVisible); + + while (currentIndex < typeNameLength) { + typeBinding = getMemberType(compoundName[currentIndex++], typeBinding); + if (!typeBinding.isValidBinding()) { + if (typeBinding instanceof ProblemReferenceBinding) { + ProblemReferenceBinding problemBinding = (ProblemReferenceBinding) typeBinding; + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + problemBinding.original, + typeBinding.problemId()); + } + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + typeBinding.problemId()); + } + } + return typeBinding; + } + + /* Internal use only + */ + final Binding getTypeOrPackage(char[] name, int mask) { + Scope scope = this; + ReferenceBinding foundType = null; + if ((mask & TYPE) == 0) { + Scope next = scope; + while ((next = scope.parent) != null) + scope = next; + } else { + done : while (true) { // done when a COMPILATION_UNIT_SCOPE is found + switch (scope.kind) { + case METHOD_SCOPE : + case BLOCK_SCOPE : + ReferenceBinding localType = ((BlockScope) scope).findLocalType(name); // looks in this scope only + if (localType != null) { + if (foundType != null && foundType != localType) + return new ProblemReferenceBinding(name, InheritedNameHidesEnclosingName); + return localType; + } + break; + case CLASS_SCOPE : + SourceTypeBinding sourceType = ((ClassScope) scope).referenceContext.binding; + // 6.5.5.1 - simple name favors member type over top-level type in same unit + ReferenceBinding memberType = findMemberType(name, sourceType); + if (memberType != null) { // skip it if we did not find anything + if (memberType.problemId() == Ambiguous) { + if (foundType == null || foundType.problemId() == NotVisible) + // supercedes any potential InheritedNameHidesEnclosingName problem + return memberType; + // make the user qualify the type, likely wants the first inherited type + return new ProblemReferenceBinding(name, InheritedNameHidesEnclosingName); + } + if (memberType.isValidBinding()) { + if (sourceType == memberType.enclosingType() + || environment().options.complianceLevel >= ClassFileConstants.JDK1_4) { + // found a valid type in the 'immediate' scope (ie. not inherited) + // OR in 1.4 mode (inherited shadows enclosing) + if (foundType == null) + return memberType; + if (foundType.isValidBinding()) + // if a valid type was found, complain when another is found in an 'immediate' enclosing type (ie. not inherited) + if (foundType != memberType) + return new ProblemReferenceBinding(name, InheritedNameHidesEnclosingName); + } + } + if (foundType == null || (foundType.problemId() == NotVisible && memberType.problemId() != NotVisible)) + // only remember the memberType if its the first one found or the previous one was not visible & memberType is... + foundType = memberType; + } + if (CharOperation.equals(sourceType.sourceName, name)) { + if (foundType != null && foundType != sourceType && foundType.problemId() != NotVisible) + return new ProblemReferenceBinding(name, InheritedNameHidesEnclosingName); + return sourceType; + } + break; + case COMPILATION_UNIT_SCOPE : + break done; + } + scope = scope.parent; + } + if (foundType != null && foundType.problemId() != NotVisible) + return foundType; + } + + // at this point the scope is a compilation unit scope + CompilationUnitScope unitScope = (CompilationUnitScope) scope; + PackageBinding currentPackage = unitScope.fPackage; + // ask for the imports + name + if ((mask & TYPE) != 0) { + // check single type imports. + + ImportBinding[] imports = unitScope.imports; + if (imports != null) { + HashtableOfObject typeImports = unitScope.resolvedSingeTypeImports; + if (typeImports != null) { + ImportBinding typeImport = (ImportBinding) typeImports.get(name); + if (typeImport != null) { + ImportReference importReference = typeImport.reference; + if (importReference != null) importReference.used = true; + return typeImport.resolvedImport; // already know its visible + } + } else { + // walk all the imports since resolvedSingeTypeImports is not yet initialized + for (int i = 0, length = imports.length; i < length; i++) { + ImportBinding typeImport = imports[i]; + if (!typeImport.onDemand) { + if (CharOperation.equals(typeImport.compoundName[typeImport.compoundName.length - 1], name)) { + if (unitScope.resolveSingleTypeImport(typeImport) != null) { + ImportReference importReference = typeImport.reference; + if (importReference != null) importReference.used = true; + return typeImport.resolvedImport; // already know its visible + } + } + } + } + } + } + // check if the name is in the current package, skip it if its a sub-package + unitScope.recordReference(currentPackage.compoundName, name); + Binding binding = currentPackage.getTypeOrPackage(name); + if (binding instanceof ReferenceBinding) return binding; // type is always visible to its own package + + // check on demand imports + if (imports != null) { + boolean foundInImport = false; + ReferenceBinding type = null; + for (int i = 0, length = imports.length; i < length; i++) { + ImportBinding someImport = imports[i]; + if (someImport.onDemand) { + Binding resolvedImport = someImport.resolvedImport; + ReferenceBinding temp = resolvedImport instanceof PackageBinding + ? findType(name, (PackageBinding) resolvedImport, currentPackage) + : findDirectMemberType(name, (ReferenceBinding) resolvedImport); + if (temp != null) { + if (temp.isValidBinding()) { + ImportReference importReference = someImport.reference; + if (importReference != null) importReference.used = true; + if (foundInImport) + // Answer error binding -- import on demand conflict; name found in two import on demand packages. + return new ProblemReferenceBinding(name, Ambiguous); + type = temp; + foundInImport = true; + } else if (foundType == null) { + foundType = temp; + } + } + } + } + if (type != null) return type; + } + } + + unitScope.recordSimpleReference(name); + if ((mask & PACKAGE) != 0) { + PackageBinding packageBinding = unitScope.environment.getTopLevelPackage(name); + if (packageBinding != null) return packageBinding; + } + + // Answer error binding -- could not find name + if (foundType != null) return foundType; // problem type from above + return new ProblemReferenceBinding(name, NotFound); + } + + // Added for code assist... NOT Public API + public final Binding getTypeOrPackage(char[][] compoundName) { + int nameLength = compoundName.length; + if (nameLength == 1) { + TypeBinding binding = getBaseType(compoundName[0]); + if (binding != null) return binding; + } + Binding binding = getTypeOrPackage(compoundName[0], TYPE | PACKAGE); + if (!binding.isValidBinding()) return binding; + + int currentIndex = 1; + boolean checkVisibility = false; + if (binding instanceof PackageBinding) { + PackageBinding packageBinding = (PackageBinding) binding; + + while (currentIndex < nameLength) { + binding = packageBinding.getTypeOrPackage(compoundName[currentIndex++]); + if (binding == null) + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + NotFound); + if (!binding.isValidBinding()) + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + binding.problemId()); + if (!(binding instanceof PackageBinding)) + break; + packageBinding = (PackageBinding) binding; + } + if (binding instanceof PackageBinding) return binding; + checkVisibility = true; + } + // binding is now a ReferenceBinding + ReferenceBinding typeBinding = (ReferenceBinding) binding; + if (checkVisibility) // handles the fall through case + if (!typeBinding.canBeSeenBy(this)) + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + typeBinding, + NotVisible); + + while (currentIndex < nameLength) { + typeBinding = getMemberType(compoundName[currentIndex++], typeBinding); + // checks visibility + if (!typeBinding.isValidBinding()) + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + typeBinding.problemId()); + } + return typeBinding; + } + + /* Answer true if the scope is nested inside a given field declaration. + * Note: it works as long as the scope.fieldDeclarationIndex is reflecting the field being traversed + * e.g. during name resolution. + */ + public final boolean isDefinedInField(FieldBinding field) { + Scope scope = this; + do { + if (scope instanceof MethodScope) { + MethodScope methodScope = (MethodScope) scope; + if (methodScope.initializedField == field) return true; + } + scope = scope.parent; + } while (scope != null); + return false; + } + + /* Answer true if the scope is nested inside a given method declaration + */ + public final boolean isDefinedInMethod(MethodBinding method) { + Scope scope = this; + do { + if (scope instanceof MethodScope) { + ReferenceContext refContext = ((MethodScope) scope).referenceContext; + if (refContext instanceof AbstractMethodDeclaration + && ((AbstractMethodDeclaration)refContext).binding == method) { + return true; + } + } + scope = scope.parent; + } while (scope != null); + return false; + } + + /* Answer whether the type is defined in the same compilation unit as the receiver + */ + public final boolean isDefinedInSameUnit(ReferenceBinding type) { + // find the outer most enclosing type + ReferenceBinding enclosingType = type; + while ((type = enclosingType.enclosingType()) != null) + enclosingType = type; + + // find the compilation unit scope + Scope scope, unitScope = this; + while ((scope = unitScope.parent) != null) + unitScope = scope; + + // test that the enclosingType is not part of the compilation unit + SourceTypeBinding[] topLevelTypes = + ((CompilationUnitScope) unitScope).topLevelTypes; + for (int i = topLevelTypes.length; --i >= 0;) + if (topLevelTypes[i] == enclosingType) + return true; + return false; + } + + /* Answer true if the scope is nested inside a given type declaration + */ + public final boolean isDefinedInType(ReferenceBinding type) { + Scope scope = this; + do { + if (scope instanceof ClassScope) + if (((ClassScope) scope).referenceContext.binding == type){ + return true; + } + scope = scope.parent; + } while (scope != null); + return false; + } + + public boolean isInsideDeprecatedCode(){ + switch(this.kind){ + case Scope.BLOCK_SCOPE : + case Scope.METHOD_SCOPE : + MethodScope methodScope = methodScope(); + if (!methodScope.isInsideInitializer()){ + // check method modifiers to see if deprecated + MethodBinding context = ((AbstractMethodDeclaration)methodScope.referenceContext).binding; + if (context != null && context.isViewedAsDeprecated()) { + return true; + } + } else { + SourceTypeBinding type = ((BlockScope)this).referenceType().binding; + // inside field declaration ? check field modifier to see if deprecated + if (methodScope.initializedField != null && methodScope.initializedField.isViewedAsDeprecated()) { + return true; + } + if (type != null && type.isViewedAsDeprecated()) { + return true; + } + } + break; + case Scope.CLASS_SCOPE : + ReferenceBinding context = ((ClassScope)this).referenceType().binding; + if (context != null && context.isViewedAsDeprecated()) { + return true; + } + break; + } + return false; + } + + public final MethodScope methodScope() { + Scope scope = this; + do { + if (scope instanceof MethodScope) + return (MethodScope) scope; + scope = scope.parent; + } while (scope != null); + return null; + } + + // Internal use only + /* All methods in visible are acceptable matches for the method in question... + * The methods defined by the receiver type appear before those defined by its + * superclass and so on. We want to find the one which matches best. + * + * Since the receiver type is a class, we know each method's declaring class is + * either the receiver type or one of its superclasses. It is an error if the best match + * is defined by a superclass, when a lesser match is defined by the receiver type + * or a closer superclass. + */ + protected final MethodBinding mostSpecificClassMethodBinding(MethodBinding[] visible, int visibleSize) { + + MethodBinding method = null; + MethodBinding previous = null; + + nextVisible : for (int i = 0; i < visibleSize; i++) { + method = visible[i]; + + if (previous != null && method.declaringClass != previous.declaringClass) + break; // cannot answer a method farther up the hierarchy than the first method found + if (!method.isStatic()) previous = method; // no ambiguity for static methods + for (int j = 0; j < visibleSize; j++) { + if (i == j) continue; + MethodBinding next = visible[j]; + if (!areParametersAssignable(next.parameters, method.parameters)) + continue nextVisible; + } + compilationUnitScope().recordTypeReferences(method.thrownExceptions); + return method; + } + return new ProblemMethodBinding(visible[0].selector, visible[0].parameters, Ambiguous); + } + + // Internal use only + /* All methods in visible are acceptable matches for the method in question... + * Since the receiver type is an interface, we ignore the possibility that 2 inherited + * but unrelated superinterfaces may define the same method in acceptable but + * not identical ways... we just take the best match that we find since any class which + * implements the receiver interface MUST implement all signatures for the method... + * in which case the best match is correct. + * + * NOTE: This is different than javac... in the following example, the message send of + * bar(X) in class Y is supposed to be ambiguous. But any class which implements the + * interface I MUST implement both signatures for bar. If this class was the receiver of + * the message send instead of the interface I, then no problem would be reported. + * + interface I1 { + void bar(J j); + } + interface I2 { + // void bar(J j); + void bar(Object o); + } + interface I extends I1, I2 {} + interface J {} + + class X implements J {} + + class Y extends X { + public void foo(I i, X x) { i.bar(x); } + } + */ + protected final MethodBinding mostSpecificInterfaceMethodBinding(MethodBinding[] visible, int visibleSize) { + MethodBinding method = null; + nextVisible : for (int i = 0; i < visibleSize; i++) { + method = visible[i]; + for (int j = 0; j < visibleSize; j++) { + if (i == j) continue; + MethodBinding next = visible[j]; + if (!areParametersAssignable(next.parameters, method.parameters)) + continue nextVisible; + } + compilationUnitScope().recordTypeReferences(method.thrownExceptions); + return method; + } + return new ProblemMethodBinding(visible[0].selector, visible[0].parameters, Ambiguous); + } + + + // Internal use only + /* All methods in visible are acceptable matches for the method in question... + * Since 1.4, the inherited ambiguous case has been removed from mostSpecificClassMethodBinding + */ + protected final MethodBinding mostSpecificMethodBinding(MethodBinding[] visible, int visibleSize) { + MethodBinding method = null; + nextVisible : for (int i = 0; i < visibleSize; i++) { + method = visible[i]; + for (int j = 0; j < visibleSize; j++) { + if (i == j) continue; + MethodBinding next = visible[j]; + if (!areParametersAssignable(next.parameters, method.parameters)) + continue nextVisible; + } + compilationUnitScope().recordTypeReferences(method.thrownExceptions); + return method; + } + return new ProblemMethodBinding(visible[0].selector, visible[0].parameters, Ambiguous); + } + + public final ClassScope outerMostClassScope() { + ClassScope lastClassScope = null; + Scope scope = this; + do { + if (scope instanceof ClassScope) + lastClassScope = (ClassScope) scope; + scope = scope.parent; + } while (scope != null); + return lastClassScope; // may answer null if no class around + } + + public final MethodScope outerMostMethodScope() { + MethodScope lastMethodScope = null; + Scope scope = this; + do { + if (scope instanceof MethodScope) + lastMethodScope = (MethodScope) scope; + scope = scope.parent; + } while (scope != null); + return lastMethodScope; // may answer null if no method around + } + + public abstract ProblemReporter problemReporter(); + + public final CompilationUnitDeclaration referenceCompilationUnit() { + Scope scope, unitScope = this; + while ((scope = unitScope.parent) != null) + unitScope = scope; + return ((CompilationUnitScope) unitScope).referenceContext; + } + // start position in this scope - for ordering scopes vs. variables + int startIndex() { + return 0; + } + + /** + * Returns the immediately enclosing switchCase statement (carried by closest blockScope), + */ + public CaseStatement switchCase() { + Scope scope = this; + do { + if (scope instanceof BlockScope) + return ((BlockScope) scope).switchCase; + scope = scope.parent; + } while (scope != null); + return null; + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java new file mode 100644 index 0000000..e791f1e --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java @@ -0,0 +1,1068 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +import java.util.Enumeration; +import java.util.Hashtable; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.Argument; +import org.eclipse.jdt.internal.compiler.ast.AssertStatement; +import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration; +import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; +import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; +import org.eclipse.jdt.internal.compiler.ast.TypeReference; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.impl.Constant; +import org.eclipse.jdt.internal.compiler.problem.AbortCompilation; + +public class SourceTypeBinding extends ReferenceBinding { + public ReferenceBinding superclass; + public ReferenceBinding[] superInterfaces; + public FieldBinding[] fields; + public MethodBinding[] methods; + public ReferenceBinding[] memberTypes; + + public ClassScope scope; + + // Synthetics are separated into 4 categories: methods, super methods, fields, class literals and changed declaring type bindings + public final static int METHOD_EMUL = 0; + public final static int FIELD_EMUL = 1; + public final static int CLASS_LITERAL_EMUL = 2; + public final static int RECEIVER_TYPE_EMUL = 3; + + Hashtable[] synthetics; + +public SourceTypeBinding(char[][] compoundName, PackageBinding fPackage, ClassScope scope) { + this.compoundName = compoundName; + this.fPackage = fPackage; + this.fileName = scope.referenceCompilationUnit().getFileName(); + this.modifiers = scope.referenceContext.modifiers; + this.sourceName = scope.referenceContext.name; + this.scope = scope; + + // expect the fields & methods to be initialized correctly later + this.fields = NoFields; + this.methods = NoMethods; + + computeId(); +} +private void addDefaultAbstractMethod(MethodBinding abstractMethod) { + MethodBinding defaultAbstract = new MethodBinding( + abstractMethod.modifiers | AccDefaultAbstract, + abstractMethod.selector, + abstractMethod.returnType, + abstractMethod.parameters, + abstractMethod.thrownExceptions, + this); + + MethodBinding[] temp = new MethodBinding[methods.length + 1]; + System.arraycopy(methods, 0, temp, 0, methods.length); + temp[methods.length] = defaultAbstract; + methods = temp; +} +public void addDefaultAbstractMethods() { + if ((tagBits & KnowsDefaultAbstractMethods) != 0) return; + + tagBits |= KnowsDefaultAbstractMethods; + + if (isClass() && isAbstract()) { + if (fPackage.environment.options.targetJDK >= ClassFileConstants.JDK1_2) return; // no longer added for post 1.2 targets + + ReferenceBinding[][] interfacesToVisit = new ReferenceBinding[5][]; + int lastPosition = 0; + interfacesToVisit[lastPosition] = superInterfaces(); + + for (int i = 0; i <= lastPosition; i++) { + ReferenceBinding[] interfaces = interfacesToVisit[i]; + for (int j = 0, length = interfaces.length; j < length; j++) { + ReferenceBinding superType = interfaces[j]; + if (superType.isValidBinding()) { + MethodBinding[] superMethods = superType.methods(); + for (int m = superMethods.length; --m >= 0;) { + MethodBinding method = superMethods[m]; + if (!implementsMethod(method)) + addDefaultAbstractMethod(method); + } + + ReferenceBinding[] itsInterfaces = superType.superInterfaces(); + if (itsInterfaces != NoSuperInterfaces) { + if (++lastPosition == interfacesToVisit.length) + System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition); + interfacesToVisit[lastPosition] = itsInterfaces; + } + } + } + } + } +} +/* Add a new synthetic field for . +* Answer the new field or the existing field if one already existed. +*/ + +public FieldBinding addSyntheticField(LocalVariableBinding actualOuterLocalVariable) { + if (synthetics == null) { + synthetics = new Hashtable[4]; + } + if (synthetics[FIELD_EMUL] == null) { + synthetics[FIELD_EMUL] = new Hashtable(5); + } + + FieldBinding synthField = (FieldBinding) synthetics[FIELD_EMUL].get(actualOuterLocalVariable); + if (synthField == null) { + synthField = new SyntheticFieldBinding( + CharOperation.concat(SyntheticArgumentBinding.OuterLocalPrefix, actualOuterLocalVariable.name), + actualOuterLocalVariable.type, + AccPrivate | AccFinal | AccSynthetic, + this, + Constant.NotAConstant, + synthetics[FIELD_EMUL].size()); + synthetics[FIELD_EMUL].put(actualOuterLocalVariable, synthField); + } + + // ensure there is not already such a field defined by the user + boolean needRecheck; + int index = 1; + do { + needRecheck = false; + FieldBinding existingField; + if ((existingField = this.getField(synthField.name, true /*resolve*/)) != null) { + TypeDeclaration typeDecl = scope.referenceContext; + for (int i = 0, max = typeDecl.fields.length; i < max; i++) { + FieldDeclaration fieldDecl = typeDecl.fields[i]; + if (fieldDecl.binding == existingField) { + synthField.name = CharOperation.concat( + SyntheticArgumentBinding.OuterLocalPrefix, + actualOuterLocalVariable.name, + ("$" + String.valueOf(index++)).toCharArray()); //$NON-NLS-1$ + needRecheck = true; + break; + } + } + } + } while (needRecheck); + return synthField; +} +/* Add a new synthetic field for . +* Answer the new field or the existing field if one already existed. +*/ + +public FieldBinding addSyntheticField(ReferenceBinding enclosingType) { + + if (synthetics == null) { + synthetics = new Hashtable[4]; + } + if (synthetics[FIELD_EMUL] == null) { + synthetics[FIELD_EMUL] = new Hashtable(5); + } + + FieldBinding synthField = (FieldBinding) synthetics[FIELD_EMUL].get(enclosingType); + if (synthField == null) { + synthField = new SyntheticFieldBinding( + CharOperation.concat( + SyntheticArgumentBinding.EnclosingInstancePrefix, + String.valueOf(enclosingType.depth()).toCharArray()), + enclosingType, + AccDefault | AccFinal | AccSynthetic, + this, + Constant.NotAConstant, + synthetics[FIELD_EMUL].size()); + synthetics[FIELD_EMUL].put(enclosingType, synthField); + } + // ensure there is not already such a field defined by the user + FieldBinding existingField; + if ((existingField = this.getField(synthField.name, true /*resolve*/)) != null) { + TypeDeclaration typeDecl = scope.referenceContext; + for (int i = 0, max = typeDecl.fields.length; i < max; i++) { + FieldDeclaration fieldDecl = typeDecl.fields[i]; + if (fieldDecl.binding == existingField) { + scope.problemReporter().duplicateFieldInType(this, fieldDecl); + break; + } + } + } + return synthField; +} +/* Add a new synthetic field for a class literal access. +* Answer the new field or the existing field if one already existed. +*/ + +public FieldBinding addSyntheticField(TypeBinding targetType, BlockScope blockScope) { + + if (synthetics == null) { + synthetics = new Hashtable[4]; + } + if (synthetics[CLASS_LITERAL_EMUL] == null) { + synthetics[CLASS_LITERAL_EMUL] = new Hashtable(5); + } + + // use a different table than FIELDS, given there might be a collision between emulation of X.this$0 and X.class. + FieldBinding synthField = (FieldBinding) synthetics[CLASS_LITERAL_EMUL].get(targetType); + if (synthField == null) { + synthField = new SyntheticFieldBinding( + ("class$" + synthetics[CLASS_LITERAL_EMUL].size()).toCharArray(), //$NON-NLS-1$ + blockScope.getJavaLangClass(), + AccDefault | AccStatic | AccSynthetic, + this, + Constant.NotAConstant, + synthetics[CLASS_LITERAL_EMUL].size()); + synthetics[CLASS_LITERAL_EMUL].put(targetType, synthField); + } + // ensure there is not already such a field defined by the user + FieldBinding existingField; + if ((existingField = this.getField(synthField.name, true /*resolve*/)) != null) { + TypeDeclaration typeDecl = blockScope.referenceType(); + for (int i = 0, max = typeDecl.fields.length; i < max; i++) { + FieldDeclaration fieldDecl = typeDecl.fields[i]; + if (fieldDecl.binding == existingField) { + blockScope.problemReporter().duplicateFieldInType(this, fieldDecl); + break; + } + } + } + return synthField; +} + +/* Add a new synthetic field for the emulation of the assert statement. +* Answer the new field or the existing field if one already existed. +*/ +public FieldBinding addSyntheticField(AssertStatement assertStatement, BlockScope blockScope) { + + if (synthetics == null) { + synthetics = new Hashtable[4]; + } + if (synthetics[FIELD_EMUL] == null) { + synthetics[FIELD_EMUL] = new Hashtable(5); + } + + FieldBinding synthField = (FieldBinding) synthetics[FIELD_EMUL].get("assertionEmulation"); //$NON-NLS-1$ + if (synthField == null) { + synthField = new SyntheticFieldBinding( + "$assertionsDisabled".toCharArray(), //$NON-NLS-1$ + BooleanBinding, + AccDefault | AccStatic | AccSynthetic | AccFinal, + this, + Constant.NotAConstant, + synthetics[FIELD_EMUL].size()); + synthetics[FIELD_EMUL].put("assertionEmulation", synthField); //$NON-NLS-1$ + } + // ensure there is not already such a field defined by the user + // ensure there is not already such a field defined by the user + boolean needRecheck; + int index = 0; + do { + needRecheck = false; + FieldBinding existingField; + if ((existingField = this.getField(synthField.name, true /*resolve*/)) != null) { + TypeDeclaration typeDecl = scope.referenceContext; + for (int i = 0, max = typeDecl.fields.length; i < max; i++) { + FieldDeclaration fieldDecl = typeDecl.fields[i]; + if (fieldDecl.binding == existingField) { + synthField.name = CharOperation.concat( + "$assertionsDisabled".toCharArray(), //$NON-NLS-1$ + ("_" + String.valueOf(index++)).toCharArray()); //$NON-NLS-1$ + needRecheck = true; + break; + } + } + } + } while (needRecheck); + return synthField; +} + +/* Add a new synthetic access method for read/write access to . + Answer the new method or the existing method if one already existed. +*/ + +public SyntheticAccessMethodBinding addSyntheticMethod(FieldBinding targetField, boolean isReadAccess) { + + if (synthetics == null) { + synthetics = new Hashtable[4]; + } + if (synthetics[METHOD_EMUL] == null) { + synthetics[METHOD_EMUL] = new Hashtable(5); + } + + SyntheticAccessMethodBinding accessMethod = null; + SyntheticAccessMethodBinding[] accessors = (SyntheticAccessMethodBinding[]) synthetics[METHOD_EMUL].get(targetField); + if (accessors == null) { + accessMethod = new SyntheticAccessMethodBinding(targetField, isReadAccess, this); + synthetics[METHOD_EMUL].put(targetField, accessors = new SyntheticAccessMethodBinding[2]); + accessors[isReadAccess ? 0 : 1] = accessMethod; + } else { + if ((accessMethod = accessors[isReadAccess ? 0 : 1]) == null) { + accessMethod = new SyntheticAccessMethodBinding(targetField, isReadAccess, this); + accessors[isReadAccess ? 0 : 1] = accessMethod; + } + } + return accessMethod; +} +/* Add a new synthetic access method for access to . + * Must distinguish access method used for super access from others (need to use invokespecial bytecode) + Answer the new method or the existing method if one already existed. +*/ + +public SyntheticAccessMethodBinding addSyntheticMethod(MethodBinding targetMethod, boolean isSuperAccess) { + + if (synthetics == null) { + synthetics = new Hashtable[4]; + } + if (synthetics[METHOD_EMUL] == null) { + synthetics[METHOD_EMUL] = new Hashtable(5); + } + + SyntheticAccessMethodBinding accessMethod = null; + SyntheticAccessMethodBinding[] accessors = (SyntheticAccessMethodBinding[]) synthetics[METHOD_EMUL].get(targetMethod); + if (accessors == null) { + accessMethod = new SyntheticAccessMethodBinding(targetMethod, isSuperAccess, this); + synthetics[METHOD_EMUL].put(targetMethod, accessors = new SyntheticAccessMethodBinding[2]); + accessors[isSuperAccess ? 0 : 1] = accessMethod; + } else { + if ((accessMethod = accessors[isSuperAccess ? 0 : 1]) == null) { + accessMethod = new SyntheticAccessMethodBinding(targetMethod, isSuperAccess, this); + accessors[isSuperAccess ? 0 : 1] = accessMethod; + } + } + return accessMethod; +} + +public FieldBinding[] availableFields() { + return fields(); +} +public MethodBinding[] availableMethods() { + return methods(); +} +void faultInTypesForFieldsAndMethods() { + fields(); + methods(); + + for (int i = 0, length = memberTypes.length; i < length; i++) + ((SourceTypeBinding) memberTypes[i]).faultInTypesForFieldsAndMethods(); +} +// NOTE: the type of each field of a source type is resolved when needed + +public FieldBinding[] fields() { + + try { + int failed = 0; + for (int f = 0, max = fields.length; f < max; f++) { + if (resolveTypeFor(fields[f]) == null) { + fields[f] = null; + failed++; + } + } + if (failed > 0) { + int newSize = fields.length - failed; + if (newSize == 0) + return fields = NoFields; + + FieldBinding[] newFields = new FieldBinding[newSize]; + for (int i = 0, n = 0, max = fields.length; i < max; i++) + if (fields[i] != null) + newFields[n++] = fields[i]; + fields = newFields; + } + } catch(AbortCompilation e){ + // ensure null fields are removed + FieldBinding[] newFields = null; + int count = 0; + for (int i = 0, max = fields.length; i < max; i++){ + FieldBinding field = fields[i]; + if (field == null && newFields == null){ + System.arraycopy(fields, 0, newFields = new FieldBinding[max], 0, i); + } else if (newFields != null && field != null) { + newFields[count++] = field; + } + } + if (newFields != null){ + System.arraycopy(newFields, 0, fields = new FieldBinding[count], 0, count); + } + throw e; + } + return fields; +} +public MethodBinding[] getDefaultAbstractMethods() { + int count = 0; + for (int i = methods.length; --i >= 0;) + if (methods[i].isDefaultAbstract()) + count++; + if (count == 0) return NoMethods; + + MethodBinding[] result = new MethodBinding[count]; + count = 0; + for (int i = methods.length; --i >= 0;) + if (methods[i].isDefaultAbstract()) + result[count++] = methods[i]; + return result; +} +// NOTE: the return type, arg & exception types of each method of a source type are resolved when needed + +public MethodBinding getExactConstructor(TypeBinding[] argumentTypes) { + int argCount = argumentTypes.length; + + if ((modifiers & AccUnresolved) == 0) { // have resolved all arg types & return type of the methods + nextMethod : for (int m = methods.length; --m >= 0;) { + MethodBinding method = methods[m]; + if (method.selector == ConstructorDeclaration.ConstantPoolName && method.parameters.length == argCount) { + TypeBinding[] toMatch = method.parameters; + for (int p = 0; p < argCount; p++) + if (toMatch[p] != argumentTypes[p]) + continue nextMethod; + return method; + } + } + } else { + MethodBinding[] constructors = getMethods(ConstructorDeclaration.ConstantPoolName); // takes care of duplicates & default abstract methods + nextConstructor : for (int c = constructors.length; --c >= 0;) { + MethodBinding constructor = constructors[c]; + TypeBinding[] toMatch = constructor.parameters; + if (toMatch.length == argCount) { + for (int p = 0; p < argCount; p++) + if (toMatch[p] != argumentTypes[p]) + continue nextConstructor; + return constructor; + } + } + } + return null; +} +// NOTE: the return type, arg & exception types of each method of a source type are resolved when needed +// searches up the hierarchy as long as no potential (but not exact) match was found. + +public MethodBinding getExactMethod(char[] selector, TypeBinding[] argumentTypes) { + int argCount = argumentTypes.length; + int selectorLength = selector.length; + boolean foundNothing = true; + + if ((modifiers & AccUnresolved) == 0) { // have resolved all arg types & return type of the methods + nextMethod : for (int m = methods.length; --m >= 0;) { + MethodBinding method = methods[m]; + if (method.selector.length == selectorLength && CharOperation.equals(method.selector, selector)) { + foundNothing = false; // inner type lookups must know that a method with this name exists + if (method.parameters.length == argCount) { + TypeBinding[] toMatch = method.parameters; + for (int p = 0; p < argCount; p++) + if (toMatch[p] != argumentTypes[p]) + continue nextMethod; + return method; + } + } + } + } else { + MethodBinding[] matchingMethods = getMethods(selector); // takes care of duplicates & default abstract methods + foundNothing = matchingMethods == NoMethods; + nextMethod : for (int m = matchingMethods.length; --m >= 0;) { + MethodBinding method = matchingMethods[m]; + TypeBinding[] toMatch = method.parameters; + if (toMatch.length == argCount) { + for (int p = 0; p < argCount; p++) + if (toMatch[p] != argumentTypes[p]) + continue nextMethod; + return method; + } + } + } + + if (foundNothing) { + if (isInterface()) { + if (superInterfaces.length == 1) + return superInterfaces[0].getExactMethod(selector, argumentTypes); + } else if (superclass != null) { + return superclass.getExactMethod(selector, argumentTypes); + } + } + return null; +} +// NOTE: the type of a field of a source type is resolved when needed + +public FieldBinding getField(char[] fieldName, boolean needResolve) { + // always resolve anyway on source types + int fieldLength = fieldName.length; + for (int f = fields.length; --f >= 0;) { + FieldBinding field = fields[f]; + if (field.name.length == fieldLength && CharOperation.equals(field.name, fieldName)) { + if (resolveTypeFor(field) != null) + return field; + + int newSize = fields.length - 1; + if (newSize == 0) { + fields = NoFields; + } else { + FieldBinding[] newFields = new FieldBinding[newSize]; + System.arraycopy(fields, 0, newFields, 0, f); + System.arraycopy(fields, f + 1, newFields, f, newSize - f); + fields = newFields; + } + return null; + } + } + return null; +} +// NOTE: the return type, arg & exception types of each method of a source type are resolved when needed + +public MethodBinding[] getMethods(char[] selector) { + // handle forward references to potential default abstract methods + addDefaultAbstractMethods(); + + try{ + int count = 0; + int lastIndex = -1; + int selectorLength = selector.length; + if ((modifiers & AccUnresolved) == 0) { // have resolved all arg types & return type of the methods + for (int m = 0, length = methods.length; m < length; m++) { + MethodBinding method = methods[m]; + if (method.selector.length == selectorLength && CharOperation.equals(method.selector, selector)) { + count++; + lastIndex = m; + } + } + } else { + boolean foundProblem = false; + int failed = 0; + for (int m = 0, length = methods.length; m < length; m++) { + MethodBinding method = methods[m]; + if (method.selector.length == selectorLength && CharOperation.equals(method.selector, selector)) { + if (resolveTypesFor(method) == null) { + foundProblem = true; + methods[m] = null; // unable to resolve parameters + failed++; + } else if (method.returnType == null) { + foundProblem = true; + } else { + count++; + lastIndex = m; + } + } + } + + if (foundProblem || count > 1) { + for (int m = methods.length; --m >= 0;) { + MethodBinding method = methods[m]; + if (method != null && method.selector.length == selectorLength && CharOperation.equals(method.selector, selector)) { + AbstractMethodDeclaration methodDecl = null; + for (int i = 0; i < m; i++) { + MethodBinding method2 = methods[i]; + if (method2 != null && CharOperation.equals(method.selector, method2.selector)) { + if (method.areParametersEqual(method2)) { + if (methodDecl == null) { + methodDecl = method.sourceMethod(); // cannot be retrieved after binding is lost + scope.problemReporter().duplicateMethodInType(this, methodDecl); + methodDecl.binding = null; + methods[m] = null; + failed++; + } + scope.problemReporter().duplicateMethodInType(this, method2.sourceMethod()); + method2.sourceMethod().binding = null; + methods[i] = null; + failed++; + } + } + } + if (method.returnType == null && methodDecl == null) { // forget method with invalid return type... was kept to detect possible collisions + method.sourceMethod().binding = null; + methods[m] = null; + failed++; + } + } + } + + if (failed > 0) { + int newSize = methods.length - failed; + if (newSize == 0) + return methods = NoMethods; + + MethodBinding[] newMethods = new MethodBinding[newSize]; + for (int i = 0, n = 0, max = methods.length; i < max; i++) + if (methods[i] != null) + newMethods[n++] = methods[i]; + methods = newMethods; + return getMethods(selector); // try again now that the problem methods have been removed + } + } + } + if (count == 1) + return new MethodBinding[] {methods[lastIndex]}; + if (count > 1) { + MethodBinding[] result = new MethodBinding[count]; + count = 0; + for (int m = 0; m <= lastIndex; m++) { + MethodBinding method = methods[m]; + if (method.selector.length == selectorLength && CharOperation.equals(method.selector, selector)) + result[count++] = method; + } + return result; + } + } catch(AbortCompilation e){ + // ensure null methods are removed + MethodBinding[] newMethods = null; + int count = 0; + for (int i = 0, max = methods.length; i < max; i++){ + MethodBinding method = methods[i]; + if (method == null && newMethods == null){ + System.arraycopy(methods, 0, newMethods = new MethodBinding[max], 0, i); + } else if (newMethods != null && method != null) { + newMethods[count++] = method; + } + } + if (newMethods != null){ + System.arraycopy(newMethods, 0, methods = new MethodBinding[count], 0, count); + } + modifiers ^= AccUnresolved; + throw e; + } + return NoMethods; +} +/* Answer the synthetic field for +* or null if one does not exist. +*/ + +public FieldBinding getSyntheticField(LocalVariableBinding actualOuterLocalVariable) { + + if (synthetics == null || synthetics[FIELD_EMUL] == null) return null; + return (FieldBinding) synthetics[FIELD_EMUL].get(actualOuterLocalVariable); +} +public ReferenceBinding[] memberTypes() { + return this.memberTypes; +} +public FieldBinding getUpdatedFieldBinding(FieldBinding targetField, ReferenceBinding newDeclaringClass) { + + if (this.synthetics == null) { + this.synthetics = new Hashtable[4]; + } + if (this.synthetics[RECEIVER_TYPE_EMUL] == null) { + this.synthetics[RECEIVER_TYPE_EMUL] = new Hashtable(5); + } + + Hashtable fieldMap = (Hashtable) this.synthetics[RECEIVER_TYPE_EMUL].get(targetField); + if (fieldMap == null) { + fieldMap = new Hashtable(5); + this.synthetics[RECEIVER_TYPE_EMUL].put(targetField, fieldMap); + } + FieldBinding updatedField = (FieldBinding) fieldMap.get(newDeclaringClass); + if (updatedField == null){ + updatedField = new FieldBinding(targetField, newDeclaringClass); + fieldMap.put(newDeclaringClass, updatedField); + } + return updatedField; +} + +public MethodBinding getUpdatedMethodBinding(MethodBinding targetMethod, ReferenceBinding newDeclaringClass) { + + if (this.synthetics == null) { + this.synthetics = new Hashtable[4]; + } + if (this.synthetics[RECEIVER_TYPE_EMUL] == null) { + this.synthetics[RECEIVER_TYPE_EMUL] = new Hashtable(5); + } + + + Hashtable methodMap = (Hashtable) synthetics[RECEIVER_TYPE_EMUL].get(targetMethod); + if (methodMap == null) { + methodMap = new Hashtable(5); + this.synthetics[RECEIVER_TYPE_EMUL].put(targetMethod, methodMap); + } + MethodBinding updatedMethod = (MethodBinding) methodMap.get(newDeclaringClass); + if (updatedMethod == null){ + updatedMethod = new MethodBinding(targetMethod, newDeclaringClass); + methodMap.put(newDeclaringClass, updatedMethod); + } + return updatedMethod; +} +public boolean hasMemberTypes() { + return this.memberTypes.length > 0; +} +// NOTE: the return type, arg & exception types of each method of a source type are resolved when needed +public MethodBinding[] methods() { + try { + if ((modifiers & AccUnresolved) == 0) + return methods; + + int failed = 0; + for (int m = 0, max = methods.length; m < max; m++) { + if (resolveTypesFor(methods[m]) == null) { + methods[m] = null; // unable to resolve parameters + failed++; + } + } + + for (int m = methods.length; --m >= 0;) { + MethodBinding method = methods[m]; + if (method != null) { + AbstractMethodDeclaration methodDecl = null; + for (int i = 0; i < m; i++) { + MethodBinding method2 = methods[i]; + if (method2 != null && CharOperation.equals(method.selector, method2.selector)) { + if (method.areParametersEqual(method2)) { + if (methodDecl == null) { + methodDecl = method.sourceMethod(); // cannot be retrieved after binding is lost + scope.problemReporter().duplicateMethodInType(this, methodDecl); + methodDecl.binding = null; + methods[m] = null; + failed++; + } + scope.problemReporter().duplicateMethodInType(this, method2.sourceMethod()); + method2.sourceMethod().binding = null; + methods[i] = null; + failed++; + } + } + } + if (method.returnType == null && methodDecl == null) { // forget method with invalid return type... was kept to detect possible collisions + method.sourceMethod().binding = null; + methods[m] = null; + failed++; + } + } + } + + if (failed > 0) { + int newSize = methods.length - failed; + if (newSize == 0) { + methods = NoMethods; + } else { + MethodBinding[] newMethods = new MethodBinding[newSize]; + for (int m = 0, n = 0, max = methods.length; m < max; m++) + if (methods[m] != null) + newMethods[n++] = methods[m]; + methods = newMethods; + } + } + + // handle forward references to potential default abstract methods + addDefaultAbstractMethods(); + } catch(AbortCompilation e){ + // ensure null methods are removed + MethodBinding[] newMethods = null; + int count = 0; + for (int i = 0, max = methods.length; i < max; i++){ + MethodBinding method = methods[i]; + if (method == null && newMethods == null){ + System.arraycopy(methods, 0, newMethods = new MethodBinding[max], 0, i); + } else if (newMethods != null && method != null) { + newMethods[count++] = method; + } + } + if (newMethods != null){ + System.arraycopy(newMethods, 0, methods = new MethodBinding[count], 0, count); + } + modifiers ^= AccUnresolved; + throw e; + } + modifiers ^= AccUnresolved; + return methods; +} +private FieldBinding resolveTypeFor(FieldBinding field) { + if ((field.modifiers & AccUnresolved) == 0) + return field; + + FieldDeclaration[] fieldDecls = scope.referenceContext.fields; + for (int f = 0, length = fieldDecls.length; f < length; f++) { + if (fieldDecls[f].binding != field) + continue; + + field.type = fieldDecls[f].getTypeBinding(scope); + field.modifiers ^= AccUnresolved; + if (!field.type.isValidBinding()) { + scope.problemReporter().fieldTypeProblem(this, fieldDecls[f], field.type); + //scope.problemReporter().invalidType(fieldDecls[f].type, field.type); + fieldDecls[f].binding = null; + return null; + } + if (field.type == VoidBinding) { + scope.problemReporter().variableTypeCannotBeVoid(fieldDecls[f]); + fieldDecls[f].binding = null; + return null; + } + if (field.type.isArrayType() && ((ArrayBinding) field.type).leafComponentType == VoidBinding) { + scope.problemReporter().variableTypeCannotBeVoidArray(fieldDecls[f]); + fieldDecls[f].binding = null; + return null; + } + return field; + } + return null; // should never reach this point +} +private MethodBinding resolveTypesFor(MethodBinding method) { + if ((method.modifiers & AccUnresolved) == 0) + return method; + + AbstractMethodDeclaration methodDecl = method.sourceMethod(); + TypeReference[] exceptionTypes = methodDecl.thrownExceptions; + if (exceptionTypes != null) { + int size = exceptionTypes.length; + method.thrownExceptions = new ReferenceBinding[size]; + ReferenceBinding throwable = scope.getJavaLangThrowable(); + int count = 0; + ReferenceBinding resolvedExceptionType; + for (int i = 0; i < size; i++) { + resolvedExceptionType = (ReferenceBinding) exceptionTypes[i].getTypeBinding(scope); + if (!resolvedExceptionType.isValidBinding()) { + methodDecl.scope.problemReporter().exceptionTypeProblem(this, methodDecl, exceptionTypes[i], resolvedExceptionType); + //methodDecl.scope.problemReporter().invalidType(exceptionTypes[i], resolvedExceptionType); + continue; + } + if (throwable != resolvedExceptionType && !throwable.isSuperclassOf(resolvedExceptionType)) { + methodDecl.scope.problemReporter().cannotThrowType(this, methodDecl, exceptionTypes[i], resolvedExceptionType); + continue; + } + method.thrownExceptions[count++] = resolvedExceptionType; + } + if (count < size) + System.arraycopy(method.thrownExceptions, 0, method.thrownExceptions = new ReferenceBinding[count], 0, count); + } + + boolean foundArgProblem = false; + Argument[] arguments = methodDecl.arguments; + if (arguments != null) { + int size = arguments.length; + method.parameters = new TypeBinding[size]; + for (int i = 0; i < size; i++) { + Argument arg = arguments[i]; + method.parameters[i] = arg.type.getTypeBinding(scope); + if (!method.parameters[i].isValidBinding()) { + methodDecl.scope.problemReporter().argumentTypeProblem(this, methodDecl, arg, method.parameters[i]); + //methodDecl.scope.problemReporter().invalidType(arg, method.parameters[i]); + foundArgProblem = true; + } else if (method.parameters[i] == VoidBinding) { + methodDecl.scope.problemReporter().argumentTypeCannotBeVoid(this, methodDecl, arg); + foundArgProblem = true; + } else if (method.parameters[i].isArrayType() && ((ArrayBinding) method.parameters[i]).leafComponentType == VoidBinding) { + methodDecl.scope.problemReporter().argumentTypeCannotBeVoidArray(this, methodDecl, arg); + foundArgProblem = true; + } + } + } + + boolean foundReturnTypeProblem = false; + if (!method.isConstructor()) { + TypeReference returnType = ((MethodDeclaration) methodDecl).returnType; + if (returnType == null) { + methodDecl.scope.problemReporter().missingReturnType(methodDecl); + method.returnType = null; + foundReturnTypeProblem = true; + } else { + method.returnType = returnType.getTypeBinding(scope); + if (!method.returnType.isValidBinding()) { + methodDecl.scope.problemReporter().returnTypeProblem(this, (MethodDeclaration) methodDecl, method.returnType); + //methodDecl.scope.problemReporter().invalidType(returnType, method.returnType); + method.returnType = null; + foundReturnTypeProblem = true; + } else if (method.returnType.isArrayType() && ((ArrayBinding) method.returnType).leafComponentType == VoidBinding) { + methodDecl.scope.problemReporter().returnTypeCannotBeVoidArray(this, (MethodDeclaration) methodDecl); + method.returnType = null; + foundReturnTypeProblem = true; + } + } + } + if (foundArgProblem) { + methodDecl.binding = null; + return null; + } + if (foundReturnTypeProblem) + return method; // but its still unresolved with a null return type & is still connected to its method declaration + + method.modifiers ^= AccUnresolved; + return method; +} +public final int sourceEnd() { + return scope.referenceContext.sourceEnd; +} +public final int sourceStart() { + return scope.referenceContext.sourceStart; +} +public ReferenceBinding superclass() { + return superclass; +} +public ReferenceBinding[] superInterfaces() { + return superInterfaces; +} +public SyntheticAccessMethodBinding[] syntheticAccessMethods() { + + if (synthetics == null || synthetics[METHOD_EMUL] == null || synthetics[METHOD_EMUL].size() == 0) return null; + + // difficult to compute size up front because of the embedded arrays so assume there is only 1 + int index = 0; + SyntheticAccessMethodBinding[] bindings = new SyntheticAccessMethodBinding[1]; + Enumeration fieldsOrMethods = synthetics[METHOD_EMUL].keys(); + while (fieldsOrMethods.hasMoreElements()) { + + Object fieldOrMethod = fieldsOrMethods.nextElement(); + + if (fieldOrMethod instanceof MethodBinding) { + + SyntheticAccessMethodBinding[] methodAccessors = (SyntheticAccessMethodBinding[]) synthetics[METHOD_EMUL].get(fieldOrMethod); + int numberOfAccessors = 0; + if (methodAccessors[0] != null) numberOfAccessors++; + if (methodAccessors[1] != null) numberOfAccessors++; + if (index + numberOfAccessors > bindings.length) + System.arraycopy(bindings, 0, (bindings = new SyntheticAccessMethodBinding[index + numberOfAccessors]), 0, index); + if (methodAccessors[0] != null) + bindings[index++] = methodAccessors[0]; // super access + if (methodAccessors[1] != null) + bindings[index++] = methodAccessors[1]; // normal access + + } else { + + SyntheticAccessMethodBinding[] fieldAccessors = (SyntheticAccessMethodBinding[]) synthetics[METHOD_EMUL].get(fieldOrMethod); + int numberOfAccessors = 0; + if (fieldAccessors[0] != null) numberOfAccessors++; + if (fieldAccessors[1] != null) numberOfAccessors++; + if (index + numberOfAccessors > bindings.length) + System.arraycopy(bindings, 0, (bindings = new SyntheticAccessMethodBinding[index + numberOfAccessors]), 0, index); + if (fieldAccessors[0] != null) + bindings[index++] = fieldAccessors[0]; // read access + if (fieldAccessors[1] != null) + bindings[index++] = fieldAccessors[1]; // write access + } + } + + // sort them in according to their own indexes + int length; + SyntheticAccessMethodBinding[] sortedBindings = new SyntheticAccessMethodBinding[length = bindings.length]; + for (int i = 0; i < length; i++){ + SyntheticAccessMethodBinding binding = bindings[i]; + sortedBindings[binding.index] = binding; + } + return sortedBindings; +} +/** + * Answer the collection of synthetic fields to append into the classfile + */ +public FieldBinding[] syntheticFields() { + + if (synthetics == null) return null; + + int fieldSize = synthetics[FIELD_EMUL] == null ? 0 : synthetics[FIELD_EMUL].size(); + int literalSize = synthetics[CLASS_LITERAL_EMUL] == null ? 0 :synthetics[CLASS_LITERAL_EMUL].size(); + int totalSize = fieldSize + literalSize; + if (totalSize == 0) return null; + FieldBinding[] bindings = new FieldBinding[totalSize]; + + // add innerclass synthetics + if (synthetics[FIELD_EMUL] != null){ + Enumeration elements = synthetics[FIELD_EMUL].elements(); + for (int i = 0; i < fieldSize; i++) { + SyntheticFieldBinding synthBinding = (SyntheticFieldBinding) elements.nextElement(); + bindings[synthBinding.index] = synthBinding; + } + } + // add class literal synthetics + if (synthetics[CLASS_LITERAL_EMUL] != null){ + Enumeration elements = synthetics[CLASS_LITERAL_EMUL].elements(); + for (int i = 0; i < literalSize; i++) { + SyntheticFieldBinding synthBinding = (SyntheticFieldBinding) elements.nextElement(); + bindings[fieldSize+synthBinding.index] = synthBinding; + } + } + return bindings; +} +public String toString() { + String s = "(id="+(id == NoId ? "NoId" : (""+id) ) +")\n"; //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-4$ //$NON-NLS-1$ + + if (isDeprecated()) s += "deprecated "; //$NON-NLS-1$ + if (isPublic()) s += "public "; //$NON-NLS-1$ + if (isProtected()) s += "protected "; //$NON-NLS-1$ + if (isPrivate()) s += "private "; //$NON-NLS-1$ + if (isAbstract() && isClass()) s += "abstract "; //$NON-NLS-1$ + if (isStatic() && isNestedType()) s += "static "; //$NON-NLS-1$ + if (isFinal()) s += "final "; //$NON-NLS-1$ + + s += isInterface() ? "interface " : "class "; //$NON-NLS-1$ //$NON-NLS-2$ + s += (compoundName != null) ? CharOperation.toString(compoundName) : "UNNAMED TYPE"; //$NON-NLS-1$ + + s += "\n\textends "; //$NON-NLS-1$ + s += (superclass != null) ? superclass.debugName() : "NULL TYPE"; //$NON-NLS-1$ + + if (superInterfaces != null) { + if (superInterfaces != NoSuperInterfaces) { + s += "\n\timplements : "; //$NON-NLS-1$ + for (int i = 0, length = superInterfaces.length; i < length; i++) { + if (i > 0) + s += ", "; //$NON-NLS-1$ + s += (superInterfaces[i] != null) ? superInterfaces[i].debugName() : "NULL TYPE"; //$NON-NLS-1$ + } + } + } else { + s += "NULL SUPERINTERFACES"; //$NON-NLS-1$ + } + + if (enclosingType() != null) { + s += "\n\tenclosing type : "; //$NON-NLS-1$ + s += enclosingType().debugName(); + } + + if (fields != null) { + if (fields != NoFields) { + s += "\n/* fields */"; //$NON-NLS-1$ + for (int i = 0, length = fields.length; i < length; i++) + s += (fields[i] != null) ? "\n" + fields[i].toString() : "\nNULL FIELD"; //$NON-NLS-1$ //$NON-NLS-2$ + } + } else { + s += "NULL FIELDS"; //$NON-NLS-1$ + } + + if (methods != null) { + if (methods != NoMethods) { + s += "\n/* methods */"; //$NON-NLS-1$ + for (int i = 0, length = methods.length; i < length; i++) + s += (methods[i] != null) ? "\n" + methods[i].toString() : "\nNULL METHOD"; //$NON-NLS-1$ //$NON-NLS-2$ + } + } else { + s += "NULL METHODS"; //$NON-NLS-1$ + } + + if (memberTypes != null) { + if (memberTypes != NoMemberTypes) { + s += "\n/* members */"; //$NON-NLS-1$ + for (int i = 0, length = memberTypes.length; i < length; i++) + s += (memberTypes[i] != null) ? "\n" + memberTypes[i].toString() : "\nNULL TYPE"; //$NON-NLS-1$ //$NON-NLS-2$ + } + } else { + s += "NULL MEMBER TYPES"; //$NON-NLS-1$ + } + + s += "\n\n\n"; //$NON-NLS-1$ + return s; +} +void verifyMethods(MethodVerifier verifier) { + verifier.verify(this); + + for (int i = memberTypes.length; --i >= 0;) + ((SourceTypeBinding) memberTypes[i]).verifyMethods(verifier); +} + +/* Answer the synthetic field for +* or null if one does not exist. +*/ + +public FieldBinding getSyntheticField(ReferenceBinding targetEnclosingType, boolean onlyExactMatch) { + + if (synthetics == null || synthetics[FIELD_EMUL] == null) return null; + FieldBinding field = (FieldBinding) synthetics[FIELD_EMUL].get(targetEnclosingType); + if (field != null) return field; + + // type compatibility : to handle cases such as + // class T { class M{}} + // class S extends T { class N extends M {}} --> need to use S as a default enclosing instance for the super constructor call in N(). + if (!onlyExactMatch){ + Enumeration accessFields = synthetics[FIELD_EMUL].elements(); + while (accessFields.hasMoreElements()) { + field = (FieldBinding) accessFields.nextElement(); + if (CharOperation.prefixEquals(SyntheticArgumentBinding.EnclosingInstancePrefix, field.name) + && targetEnclosingType.isSuperclassOf((ReferenceBinding) field.type)) + return field; + } + } + return null; +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/SyntheticAccessMethodBinding.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/SyntheticAccessMethodBinding.java new file mode 100644 index 0000000..0803da4 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/SyntheticAccessMethodBinding.java @@ -0,0 +1,288 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; + +public class SyntheticAccessMethodBinding extends MethodBinding { + + public FieldBinding targetReadField; // read access to a field + public FieldBinding targetWriteField; // write access to a field + public MethodBinding targetMethod; // method or constructor + + public int accessType; + + public final static int FieldReadAccess = 1; // field read + public final static int FieldWriteAccess = 2; // field write + public final static int MethodAccess = 3; // normal method + public final static int ConstructorAccess = 4; // constructor + public final static int SuperMethodAccess = 5; // super method + + final static char[] AccessMethodPrefix = { 'a', 'c', 'c', 'e', 's', 's', '$' }; + + public int sourceStart = 0; // start position of the matching declaration + public int index; // used for sorting access methods in the class file + + public SyntheticAccessMethodBinding(FieldBinding targetField, boolean isReadAccess, ReferenceBinding declaringClass) { + + this.modifiers = AccDefault | AccStatic | AccSynthetic; + SourceTypeBinding declaringSourceType = (SourceTypeBinding) declaringClass; + SyntheticAccessMethodBinding[] knownAccessMethods = declaringSourceType.syntheticAccessMethods(); + int methodId = knownAccessMethods == null ? 0 : knownAccessMethods.length; + this.index = methodId; + this.selector = CharOperation.concat(AccessMethodPrefix, String.valueOf(methodId).toCharArray()); + if (isReadAccess) { + this.returnType = targetField.type; + if (targetField.isStatic()) { + this.parameters = NoParameters; + } else { + this.parameters = new TypeBinding[1]; + this.parameters[0] = declaringSourceType; + } + this.targetReadField = targetField; + this.accessType = FieldReadAccess; + } else { + this.returnType = VoidBinding; + if (targetField.isStatic()) { + this.parameters = new TypeBinding[1]; + this.parameters[0] = targetField.type; + } else { + this.parameters = new TypeBinding[2]; + this.parameters[0] = declaringSourceType; + this.parameters[1] = targetField.type; + } + this.targetWriteField = targetField; + this.accessType = FieldWriteAccess; + } + this.thrownExceptions = NoExceptions; + this.declaringClass = declaringSourceType; + + // check for method collision + boolean needRename; + do { + check : { + needRename = false; + // check for collision with known methods + MethodBinding[] methods = declaringSourceType.methods; + for (int i = 0, length = methods.length; i < length; i++) { + if (CharOperation.equals(this.selector, methods[i].selector) && this.areParametersEqual(methods[i])) { + needRename = true; + break check; + } + } + // check for collision with synthetic accessors + if (knownAccessMethods != null) { + for (int i = 0, length = knownAccessMethods.length; i < length; i++) { + if (knownAccessMethods[i] == null) continue; + if (CharOperation.equals(this.selector, knownAccessMethods[i].selector) && this.areParametersEqual(methods[i])) { + needRename = true; + break check; + } + } + } + } + if (needRename) { // retry with a selector postfixed by a growing methodId + this.setSelector(CharOperation.concat(AccessMethodPrefix, String.valueOf(++methodId).toCharArray())); + } + } while (needRename); + + // retrieve sourceStart position for the target field for line number attributes + FieldDeclaration[] fieldDecls = declaringSourceType.scope.referenceContext.fields; + if (fieldDecls != null) { + for (int i = 0, max = fieldDecls.length; i < max; i++) { + if (fieldDecls[i].binding == targetField) { + this.sourceStart = fieldDecls[i].sourceStart; + return; + } + } + } + + /* did not find the target field declaration - it is a synthetic one + public class A { + public class B { + public class C { + void foo() { + System.out.println("A.this = " + A.this); + } + } + } + public static void main(String args[]) { + new A().new B().new C().foo(); + } + } + */ + // We now at this point - per construction - it is for sure an enclosing instance, we are going to + // show the target field type declaration location. + this.sourceStart = declaringSourceType.scope.referenceContext.sourceStart; // use the target declaring class name position instead + } + + public SyntheticAccessMethodBinding(MethodBinding targetMethod, boolean isSuperAccess, ReferenceBinding receiverType) { + + if (targetMethod.isConstructor()) { + this.initializeConstructorAccessor(targetMethod); + } else { + this.initializeMethodAccessor(targetMethod, isSuperAccess, receiverType); + } + } + + /** + * An constructor accessor is a constructor with an extra argument (declaringClass), in case of + * collision with an existing constructor, then add again an extra argument (declaringClass again). + */ + public void initializeConstructorAccessor(MethodBinding accessedConstructor) { + + this.targetMethod = accessedConstructor; + this.modifiers = AccDefault | AccSynthetic; + SourceTypeBinding sourceType = (SourceTypeBinding) accessedConstructor.declaringClass; + SyntheticAccessMethodBinding[] knownAccessMethods = + sourceType.syntheticAccessMethods(); + this.index = knownAccessMethods == null ? 0 : knownAccessMethods.length; + + this.selector = accessedConstructor.selector; + this.returnType = accessedConstructor.returnType; + this.accessType = ConstructorAccess; + this.parameters = new TypeBinding[accessedConstructor.parameters.length + 1]; + System.arraycopy( + accessedConstructor.parameters, + 0, + this.parameters, + 0, + accessedConstructor.parameters.length); + parameters[accessedConstructor.parameters.length] = + accessedConstructor.declaringClass; + this.thrownExceptions = accessedConstructor.thrownExceptions; + this.declaringClass = sourceType; + + // check for method collision + boolean needRename; + do { + check : { + needRename = false; + // check for collision with known methods + MethodBinding[] methods = sourceType.methods; + for (int i = 0, length = methods.length; i < length; i++) { + if (CharOperation.equals(this.selector, methods[i].selector) + && this.areParametersEqual(methods[i])) { + needRename = true; + break check; + } + } + // check for collision with synthetic accessors + if (knownAccessMethods != null) { + for (int i = 0, length = knownAccessMethods.length; i < length; i++) { + if (knownAccessMethods[i] == null) + continue; + if (CharOperation.equals(this.selector, knownAccessMethods[i].selector) + && this.areParametersEqual(knownAccessMethods[i])) { + needRename = true; + break check; + } + } + } + } + if (needRename) { // retry with a new extra argument + int length = this.parameters.length; + System.arraycopy( + this.parameters, + 0, + this.parameters = new TypeBinding[length + 1], + 0, + length); + this.parameters[length] = this.declaringClass; + } + } while (needRename); + + // retrieve sourceStart position for the target method for line number attributes + AbstractMethodDeclaration[] methodDecls = + sourceType.scope.referenceContext.methods; + if (methodDecls != null) { + for (int i = 0, length = methodDecls.length; i < length; i++) { + if (methodDecls[i].binding == accessedConstructor) { + this.sourceStart = methodDecls[i].sourceStart; + return; + } + } + } + } + + /** + * An method accessor is a method with an access$N selector, where N is incremented in case of collisions. + */ + public void initializeMethodAccessor(MethodBinding accessedMethod, boolean isSuperAccess, ReferenceBinding receiverType) { + + this.targetMethod = accessedMethod; + this.modifiers = AccDefault | AccStatic | AccSynthetic; + SourceTypeBinding declaringSourceType = (SourceTypeBinding) receiverType; + SyntheticAccessMethodBinding[] knownAccessMethods = declaringSourceType.syntheticAccessMethods(); + int methodId = knownAccessMethods == null ? 0 : knownAccessMethods.length; + this.index = methodId; + + this.selector = CharOperation.concat(AccessMethodPrefix, String.valueOf(methodId).toCharArray()); + this.returnType = accessedMethod.returnType; + this.accessType = isSuperAccess ? SuperMethodAccess : MethodAccess; + + if (accessedMethod.isStatic()) { + this.parameters = accessedMethod.parameters; + } else { + this.parameters = new TypeBinding[accessedMethod.parameters.length + 1]; + this.parameters[0] = declaringSourceType; + System.arraycopy(accessedMethod.parameters, 0, this.parameters, 1, accessedMethod.parameters.length); + } + this.thrownExceptions = accessedMethod.thrownExceptions; + this.declaringClass = declaringSourceType; + + // check for method collision + boolean needRename; + do { + check : { + needRename = false; + // check for collision with known methods + MethodBinding[] methods = declaringSourceType.methods; + for (int i = 0, length = methods.length; i < length; i++) { + if (CharOperation.equals(this.selector, methods[i].selector) && this.areParametersEqual(methods[i])) { + needRename = true; + break check; + } + } + // check for collision with synthetic accessors + if (knownAccessMethods != null) { + for (int i = 0, length = knownAccessMethods.length; i < length; i++) { + if (knownAccessMethods[i] == null) continue; + if (CharOperation.equals(this.selector, knownAccessMethods[i].selector) && this.areParametersEqual(knownAccessMethods[i])) { + needRename = true; + break check; + } + } + } + } + if (needRename) { // retry with a selector & a growing methodId + this.setSelector(CharOperation.concat(AccessMethodPrefix, String.valueOf(++methodId).toCharArray())); + } + } while (needRename); + + // retrieve sourceStart position for the target method for line number attributes + AbstractMethodDeclaration[] methodDecls = declaringSourceType.scope.referenceContext.methods; + if (methodDecls != null) { + for (int i = 0, length = methodDecls.length; i < length; i++) { + if (methodDecls[i].binding == accessedMethod) { + this.sourceStart = methodDecls[i].sourceStart; + return; + } + } + } + } + + protected boolean isConstructorRelated() { + return accessType == ConstructorAccess; + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/SyntheticArgumentBinding.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/SyntheticArgumentBinding.java new file mode 100644 index 0000000..521c6ea --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/SyntheticArgumentBinding.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +/** + * Specific local variable location used to: + * - either provide emulation for outer local variables used from within innerclass constructs, + * - or provide emulation to enclosing instances. + * When it is mapping to an outer local variable, this actual outer local is accessible through + * the public field #actualOuterLocalVariable. + * + * Such a synthetic argument binding will be inserted in all constructors of local innertypes before + * the user arguments. + */ + +import org.eclipse.jdt.core.compiler.CharOperation; + +public class SyntheticArgumentBinding extends LocalVariableBinding { + + { + this.isArgument = true; + this.useFlag = USED; + } + + // if the argument is mapping to an outer local variable, this denotes the outer actual variable + public LocalVariableBinding actualOuterLocalVariable; + // if the argument has a matching synthetic field + public FieldBinding matchingField; + + final static char[] OuterLocalPrefix = { 'v', 'a', 'l', '$' }; + final static char[] EnclosingInstancePrefix = { 't', 'h', 'i', 's', '$' }; + + public SyntheticArgumentBinding(LocalVariableBinding actualOuterLocalVariable) { + + super( + CharOperation.concat(OuterLocalPrefix, actualOuterLocalVariable.name), + actualOuterLocalVariable.type, + AccFinal, + true); + this.actualOuterLocalVariable = actualOuterLocalVariable; + } + + public SyntheticArgumentBinding(ReferenceBinding enclosingType) { + + super( + CharOperation.concat( + SyntheticArgumentBinding.EnclosingInstancePrefix, + String.valueOf(enclosingType.depth()).toCharArray()), + enclosingType, + AccFinal, + true); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/SyntheticFieldBinding.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/SyntheticFieldBinding.java new file mode 100644 index 0000000..ca40bca --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/SyntheticFieldBinding.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +import org.eclipse.jdt.internal.compiler.impl.Constant; + +public class SyntheticFieldBinding extends FieldBinding { + public int index; +public SyntheticFieldBinding(char[] name, TypeBinding type, int modifiers, ReferenceBinding declaringClass, Constant constant, int index) { + super(name, type, modifiers, declaringClass, constant); + this.index = index; +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/TagBits.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/TagBits.java new file mode 100644 index 0000000..556a7c4 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/TagBits.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +public interface TagBits { + // Tag bits in the tagBits int of every TypeBinding + final int IsArrayType = 0x0001; + final int IsBaseType = 0x0002; + final int IsNestedType = 0x0004; + final int IsMemberType = 0x0008; + final int MemberTypeMask = IsNestedType | IsMemberType; + final int IsLocalType = 0x0010; + final int LocalTypeMask = IsNestedType | IsLocalType; + final int IsAnonymousType = 0x0020; + final int AnonymousTypeMask = LocalTypeMask | IsAnonymousType; + final int IsBinaryBinding = 0x0040; + + // for the type hierarchy check used by ClassScope + final int BeginHierarchyCheck = 0x0100; + final int EndHierarchyCheck = 0x0200; + + // test bit to see if default abstract methods were computed + final int KnowsDefaultAbstractMethods = 0x0400; + + // Reusable bit currently used by Scopes + final int InterfaceVisited = 0x0800; + + // test bits to see if parts of binary types are faulted + final int AreFieldsComplete = 0x1000; + final int AreMethodsComplete = 0x2000; + + // test bit to avoid asking a type for a member type (includes inherited member types) + final int HasNoMemberTypes = 0x4000; + + // test bit to identify if the type's hierarchy is inconsistent + final int HierarchyHasProblems = 0x8000; +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java new file mode 100644 index 0000000..c6cd627 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java @@ -0,0 +1,165 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +import org.eclipse.jdt.core.compiler.CharOperation; + +/* + * Not all fields defined by this type (& its subclasses) are initialized when it is created. + * Some are initialized only when needed. + * + * Accessors have been provided for some public fields so all TypeBindings have the same API... + * but access public fields directly whenever possible. + * Non-public fields have accessors which should be used everywhere you expect the field to be initialized. + * + * null is NOT a valid value for a non-public field... it just means the field is not initialized. + */ +abstract public class TypeBinding extends Binding implements BaseTypes, TagBits, TypeConstants, TypeIds { + public int id = NoId; + public int tagBits = 0; // See values in the interface TagBits below +/* API + * Answer the receiver's binding type from Binding.BindingID. + */ + +public final int bindingType() { + return TYPE; +} +/* Answer true if the receiver can be instantiated + */ +public boolean canBeInstantiated() { + return !isBaseType(); +} +/** + * Answer the receiver's constant pool name. + * NOTE: This method should only be used during/after code gen. + * e.g. 'java/lang/Object' + */ +public abstract char[] constantPoolName(); + +String debugName() { + return new String(readableName()); +} +/* + * Answer the receiver's dimensions - 0 for non-array types + */ +public int dimensions(){ + return 0; +} +public abstract PackageBinding getPackage(); +/* Answer true if the receiver is an array +*/ + +public final boolean isArrayType() { + return (tagBits & IsArrayType) != 0; +} +/* Answer true if the receiver is a base type +*/ + +public final boolean isBaseType() { + return (tagBits & IsBaseType) != 0; +} +public boolean isClass() { + return false; +} +/* Answer true if the receiver type can be assigned to the argument type (right) +*/ + +public abstract boolean isCompatibleWith(TypeBinding right); +/* Answer true if the receiver's hierarchy has problems (always false for arrays & base types) +*/ + +public final boolean isHierarchyInconsistent() { + return (tagBits & HierarchyHasProblems) != 0; +} +public boolean isInterface() { + return false; +} +public final boolean isNumericType() { + switch (id) { + case T_int : + case T_float : + case T_double : + case T_short : + case T_byte : + case T_long : + case T_char : + return true; + default : + return false; + } +} + +public TypeBinding leafComponentType(){ + return this; +} + +/** + * Answer the qualified name of the receiver's package separated by periods + * or an empty string if its the default package. + * + * For example, {java.util.Hashtable}. + */ + +public char[] qualifiedPackageName() { + PackageBinding packageBinding = getPackage(); + return packageBinding == null || packageBinding.compoundName == CharOperation.NO_CHAR_CHAR + ? CharOperation.NO_CHAR + : packageBinding.readableName(); +} +/** +* Answer the source name for the type. +* In the case of member types, as the qualified name from its top level type. +* For example, for a member type N defined inside M & A: "A.M.N". +*/ + +public abstract char[] qualifiedSourceName(); +/* Answer the receiver's signature. +* +* Arrays & base types do not distinguish between signature() & constantPoolName(). +* +* NOTE: This method should only be used during/after code gen. +*/ + +public char[] signature() { + return constantPoolName(); +} +public abstract char[] sourceName(); + +/** + * Match a well-known type id to its binding + */ +public static final TypeBinding wellKnownType(Scope scope, int id) { + switch (id) { + case T_boolean : + return BooleanBinding; + case T_byte : + return ByteBinding; + case T_char : + return CharBinding; + case T_short : + return ShortBinding; + case T_double : + return DoubleBinding; + case T_float : + return FloatBinding; + case T_int : + return IntBinding; + case T_long : + return LongBinding; + case T_Object : + return scope.getJavaLangObject(); + case T_String : + return scope.getJavaLangString(); + default : + return null; + } + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java new file mode 100644 index 0000000..5f6064f --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +public interface TypeConstants { + final char[] JAVA = "java".toCharArray(); //$NON-NLS-1$ + final char[] LANG = "lang".toCharArray(); //$NON-NLS-1$ + final char[] IO = "io".toCharArray(); //$NON-NLS-1$ + final char[] REFLECT = "reflect".toCharArray(); //$NON-NLS-1$ + final char[] CharArray_JAVA_LANG_OBJECT = "java.lang.Object".toCharArray(); //$NON-NLS-1$ + final char[] LENGTH = "length".toCharArray(); //$NON-NLS-1$ + final char[] CLONE = "clone".toCharArray(); //$NON-NLS-1$ + final char[] OBJECT = "Object".toCharArray(); //$NON-NLS-1$ + final char[] MAIN = "main".toCharArray(); //$NON-NLS-1$ + final char[] SERIALVERSIONUID = "serialVersionUID".toCharArray(); //$NON-NLS-1$ + final char[] SERIALPERSISTENTFIELDS = "serialPersistentFields".toCharArray(); //$NON-NLS-1$ + final char[] READRESOLVE = "readResolve".toCharArray(); //$NON-NLS-1$ + final char[] WRITEREPLACE = "writeReplace".toCharArray(); //$NON-NLS-1$ + final char[] READOBJECT = "readObject".toCharArray(); //$NON-NLS-1$ + final char[] WRITEOBJECT = "writeObject".toCharArray(); //$NON-NLS-1$ + final char[] CharArray_JAVA_IO_OBJECTINPUTSTREAM = "java.io.ObjectInputStream".toCharArray(); //$NON-NLS-1$ + final char[] CharArray_JAVA_IO_OBJECTOUTPUTSTREAM = "java.io.ObjectOutputStream".toCharArray(); //$NON-NLS-1$ + final char[] CharArray_JAVA_IO_OBJECTSTREAMFIELD = "java.io.ObjectStreamField".toCharArray(); //$NON-NLS-1$ + + + // Constant compound names + final char[][] JAVA_LANG = {JAVA, LANG}; + final char[][] JAVA_IO = {JAVA, IO}; + final char[][] JAVA_LANG_ASSERTIONERROR = {JAVA, LANG, "AssertionError".toCharArray()}; //$NON-NLS-1$ + final char[][] JAVA_LANG_CLASS = {JAVA, LANG, "Class".toCharArray()}; //$NON-NLS-1$ + final char[][] JAVA_LANG_CLASSNOTFOUNDEXCEPTION = {JAVA, LANG, "ClassNotFoundException".toCharArray()}; //$NON-NLS-1$ + final char[][] JAVA_LANG_CLONEABLE = {JAVA, LANG, "Cloneable".toCharArray()}; //$NON-NLS-1$ + final char[][] JAVA_LANG_EXCEPTION = {JAVA, LANG, "Exception".toCharArray()}; //$NON-NLS-1$ + final char[][] JAVA_LANG_ERROR = {JAVA, LANG, "Error".toCharArray()}; //$NON-NLS-1$ + final char[][] JAVA_LANG_NOCLASSDEFERROR = {JAVA, LANG, "NoClassDefError".toCharArray()}; //$NON-NLS-1$ + final char[][] JAVA_LANG_OBJECT = {JAVA, LANG, OBJECT}; + final char[][] JAVA_LANG_STRING = {JAVA, LANG, "String".toCharArray()}; //$NON-NLS-1$ + final char[][] JAVA_LANG_STRINGBUFFER = {JAVA, LANG, "StringBuffer".toCharArray()}; //$NON-NLS-1$ + final char[][] JAVA_LANG_SYSTEM = {JAVA, LANG, "System".toCharArray()}; //$NON-NLS-1$ + final char[][] JAVA_LANG_RUNTIMEEXCEPTION = {JAVA, LANG, "RuntimeException".toCharArray()}; //$NON-NLS-1$ + final char[][] JAVA_LANG_THROWABLE = {JAVA, LANG, "Throwable".toCharArray()}; //$NON-NLS-1$ + final char[][] JAVA_LANG_REFLECT_CONSTRUCTOR = {JAVA, LANG, REFLECT, "Constructor".toCharArray()}; //$NON-NLS-1$ + final char[][] JAVA_IO_PRINTSTREAM = {JAVA, IO, "PrintStream".toCharArray()}; //$NON-NLS-1$ + final char[][] JAVA_IO_SERIALIZABLE = {JAVA, IO, "Serializable".toCharArray()}; //$NON-NLS-1$ + final char[][] JAVA_LANG_BYTE = {JAVA, LANG, "Byte".toCharArray()}; //$NON-NLS-1$ + final char[][] JAVA_LANG_SHORT = {JAVA, LANG, "Short".toCharArray()}; //$NON-NLS-1$ + final char[][] JAVA_LANG_CHARACTER = {JAVA, LANG, "Character".toCharArray()}; //$NON-NLS-1$ + final char[][] JAVA_LANG_INTEGER = {JAVA, LANG, "Integer".toCharArray()}; //$NON-NLS-1$ + final char[][] JAVA_LANG_LONG = {JAVA, LANG, "Long".toCharArray()}; //$NON-NLS-1$ + final char[][] JAVA_LANG_FLOAT = {JAVA, LANG, "Float".toCharArray()}; //$NON-NLS-1$ + final char[][] JAVA_LANG_DOUBLE = {JAVA, LANG, "Double".toCharArray()}; //$NON-NLS-1$ + final char[][] JAVA_LANG_BOOLEAN = {JAVA, LANG, "Boolean".toCharArray()}; //$NON-NLS-1$ + final char[][] JAVA_LANG_VOID = {JAVA, LANG, "Void".toCharArray()}; //$NON-NLS-1$ + + // Constants used by the flow analysis + final int EqualOrMoreSpecific = -1; + final int NotRelated = 0; + final int MoreGeneric = 1; + + // Method collections + final TypeBinding[] NoParameters = new TypeBinding[0]; + final ReferenceBinding[] NoExceptions = new ReferenceBinding[0]; + final ReferenceBinding[] AnyException = new ReferenceBinding[] { null }; // special handler for all exceptions + // Type collections + final FieldBinding[] NoFields = new FieldBinding[0]; + final MethodBinding[] NoMethods = new MethodBinding[0]; + final ReferenceBinding[] NoSuperInterfaces = new ReferenceBinding[0]; + final ReferenceBinding[] NoMemberTypes = new ReferenceBinding[0]; +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java new file mode 100644 index 0000000..5fe8af0 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java @@ -0,0 +1,134 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +public interface TypeIds { + //base type void null undefined Object String + //should have an id that is 0<= id <= 15 + + final int T_undefined = 0; // should not be changed + final int T_Object = 1; + final int T_char = 2; + final int T_byte = 3; + final int T_short = 4; + final int T_boolean = 5; + final int T_void = 6; + final int T_long = 7; + final int T_double = 8; + final int T_float = 9; + final int T_int = 10; + final int T_String = 11; + final int T_null = 12; + //final int T_extendedDouble = 13; + //final int T_extendedLong = 14 + + //=========end of 4 bits constraint=========== + + final int T_JavaLangObject = T_Object; // for consistency + final int T_JavaLangString = T_String; // for consistency + + // well-known exception types + final int T_JavaLangClass = 16; + final int T_JavaLangStringBuffer = 17; + final int T_JavaLangSystem = 18; + final int T_JavaLangError = 19; + final int T_JavaLangReflectConstructor = 20; + final int T_JavaLangThrowable = 21; + final int T_JavaLangNoClassDefError = 22; + final int T_JavaLangClassNotFoundException = 23; + final int T_JavaIoPrintStream = 24; + final int T_JavaLangException = 25; + + // wrapper types + final int T_JavaLangByte = 26; + final int T_JavaLangShort = 27; + final int T_JavaLangCharacter = 28; + final int T_JavaLangInteger = 29; + final int T_JavaLangLong = 30; + final int T_JavaLangFloat = 31; + final int T_JavaLangDouble = 32; + final int T_JavaLangBoolean = 33; + final int T_JavaLangVoid = 34; + + // 1.4 feature + final int T_JavaLangAssertionError = 35; + + // array interfaces + final int T_JavaLangCloneable = 36; + final int T_JavaIoSerializable = 37; + + final int NoId = Integer.MAX_VALUE; + + // implicit conversions: to (note: booleans are integers at runtime) + final int Boolean2Int = T_boolean + (T_int << 4); + final int Boolean2String = T_boolean + (T_String << 4); + final int Boolean2Boolean = T_boolean + (T_boolean << 4); + final int Byte2Byte = T_byte + (T_byte << 4); + final int Byte2Short = T_byte + (T_short << 4); + final int Byte2Char = T_byte + (T_char << 4); + final int Byte2Int = T_byte + (T_int << 4); + final int Byte2Long = T_byte + (T_long << 4); + final int Byte2Float = T_byte + (T_float << 4); + final int Byte2Double = T_byte + (T_double << 4); + final int Byte2String = T_byte + (T_String << 4); + final int Short2Byte = T_short + (T_byte << 4); + final int Short2Short = T_short + (T_short << 4); + final int Short2Char = T_short + (T_char << 4); + final int Short2Int = T_short + (T_int << 4); + final int Short2Long = T_short + (T_long << 4); + final int Short2Float = T_short + (T_float << 4); + final int Short2Double = T_short + (T_double << 4); + final int Short2String = T_short + (T_String << 4); + final int Char2Byte = T_char + (T_byte << 4); + final int Char2Short = T_char + (T_short << 4); + final int Char2Char = T_char + (T_char << 4); + final int Char2Int = T_char + (T_int << 4); + final int Char2Long = T_char + (T_long << 4); + final int Char2Float = T_char + (T_float << 4); + final int Char2Double = T_char + (T_double << 4); + final int Char2String = T_char + (T_String << 4); + final int Int2Byte = T_int + (T_byte << 4); + final int Int2Short = T_int + (T_short << 4); + final int Int2Char = T_int + (T_char << 4); + final int Int2Int = T_int + (T_int << 4); + final int Int2Long = T_int + (T_long << 4); + final int Int2Float = T_int + (T_float << 4); + final int Int2Double = T_int + (T_double << 4); + final int Int2String = T_int + (T_String << 4); + final int Long2Byte = T_long + (T_byte << 4); + final int Long2Short = T_long + (T_short << 4); + final int Long2Char = T_long + (T_char << 4); + final int Long2Int = T_long + (T_int << 4); + final int Long2Long = T_long + (T_long << 4); + final int Long2Float = T_long + (T_float << 4); + final int Long2Double = T_long + (T_double << 4); + final int Long2String = T_long + (T_String << 4); + final int Float2Byte = T_float + (T_byte << 4); + final int Float2Short = T_float + (T_short << 4); + final int Float2Char = T_float + (T_char << 4); + final int Float2Int = T_float + (T_int << 4); + final int Float2Long = T_float + (T_long << 4); + final int Float2Float = T_float + (T_float << 4); + final int Float2Double = T_float + (T_double << 4); + final int Float2String = T_float + (T_String << 4); + final int Double2Byte = T_double + (T_byte << 4); + final int Double2Short = T_double + (T_short << 4); + final int Double2Char = T_double + (T_char << 4); + final int Double2Int = T_double + (T_int << 4); + final int Double2Long = T_double + (T_long << 4); + final int Double2Float = T_double + (T_float << 4); + final int Double2Double = T_double + (T_double << 4); + final int Double2String = T_double + (T_String << 4); + final int String2String = T_String + (T_String << 4); + final int Object2String = T_Object + (T_String << 4); + final int Null2String = T_null + (T_String << 4); + final int Object2Object = T_Object + (T_Object << 4); +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/UnresolvedReferenceBinding.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/UnresolvedReferenceBinding.java new file mode 100644 index 0000000..65ff088 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/UnresolvedReferenceBinding.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +import org.eclipse.jdt.core.compiler.CharOperation; + +public class UnresolvedReferenceBinding extends ReferenceBinding { + ReferenceBinding resolvedType; +UnresolvedReferenceBinding(char[][] compoundName, PackageBinding packageBinding) { + this.compoundName = compoundName; + this.sourceName = compoundName[compoundName.length - 1]; // reasonable guess + this.fPackage = packageBinding; +} +String debugName() { + return toString(); +} +ReferenceBinding resolve(LookupEnvironment environment) { + if (resolvedType != null) return resolvedType; + + ReferenceBinding environmentType = fPackage.getType0(compoundName[compoundName.length - 1]); + if (environmentType == this) + environmentType = environment.askForType(compoundName); + if (environmentType != null && environmentType != this) { // could not resolve any better, error was already reported against it + resolvedType = environmentType; + environment.updateArrayCache(this, environmentType); + return environmentType; // when found, it replaces the unresolved type in the cache + } + + environment.problemReporter.isClassPathCorrect(compoundName, null); + return null; // will not get here since the above error aborts the compilation +} +public String toString() { + return "Unresolved type " + ((compoundName != null) ? CharOperation.toString(compoundName) : "UNNAMED"); //$NON-NLS-1$ //$NON-NLS-2$ +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/UpdatedMethodBinding.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/UpdatedMethodBinding.java new file mode 100644 index 0000000..485c159 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/UpdatedMethodBinding.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +public class UpdatedMethodBinding extends MethodBinding { + + public TypeBinding updatedDeclaringClass; + + public UpdatedMethodBinding(TypeBinding updatedDeclaringClass, int modifiers, char[] selector, TypeBinding returnType, TypeBinding[] args, ReferenceBinding[] exceptions, ReferenceBinding declaringClass) { + super(modifiers, selector, returnType, args, exceptions, declaringClass); + this.updatedDeclaringClass = updatedDeclaringClass; + } + + public TypeBinding constantPoolDeclaringClass() { + return this.updatedDeclaringClass; + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/lookup/VariableBinding.java b/src/java/org/eclipse/jdt/internal/compiler/lookup/VariableBinding.java new file mode 100644 index 0000000..2e06558 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/lookup/VariableBinding.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +import org.eclipse.jdt.internal.compiler.impl.Constant; + +public abstract class VariableBinding extends Binding { + public int modifiers; + public TypeBinding type; + public char[] name; + public Constant constant; + public int id; // for flow-analysis (position in flowInfo bit vector) + +public boolean isConstantValue() { + return constant != Constant.NotAConstant; +} + +public final boolean isBlankFinal(){ + return (modifiers & AccBlankFinal) != 0; +} +/* Answer true if the receiver is final and cannot be changed +*/ + +public final boolean isFinal() { + return (modifiers & AccFinal) != 0; +} +public char[] readableName() { + return name; +} +public String toString() { + String s = (type != null) ? type.debugName() : "UNDEFINED TYPE"; //$NON-NLS-1$ + s += " "; //$NON-NLS-1$ + s += (name != null) ? new String(name) : "UNNAMED FIELD"; //$NON-NLS-1$ + return s; +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/AbstractCommentParser.java b/src/java/org/eclipse/jdt/internal/compiler/parser/AbstractCommentParser.java new file mode 100644 index 0000000..ca99505 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/parser/AbstractCommentParser.java @@ -0,0 +1,1402 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.parser; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.core.compiler.InvalidInputException; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; + +/** + * Parser specialized for decoding javadoc comments + */ +public abstract class AbstractCommentParser { + + // recognized tags + public static final char[] TAG_DEPRECATED = "deprecated".toCharArray(); //$NON-NLS-1$ + public static final char[] TAG_PARAM = "param".toCharArray(); //$NON-NLS-1$ + public static final char[] TAG_RETURN = "return".toCharArray(); //$NON-NLS-1$ + public static final char[] TAG_THROWS = "throws".toCharArray(); //$NON-NLS-1$ + public static final char[] TAG_EXCEPTION = "exception".toCharArray(); //$NON-NLS-1$ + public static final char[] TAG_SEE = "see".toCharArray(); //$NON-NLS-1$ + public static final char[] TAG_LINK = "link".toCharArray(); //$NON-NLS-1$ + public static final char[] TAG_LINKPLAIN = "linkplain".toCharArray(); //$NON-NLS-1$ + public static final char[] TAG_INHERITDOC = "inheritDoc".toCharArray(); //$NON-NLS-1$ + + // tags expected positions + public final static int ORDERED_TAGS_NUMBER = 3; + public final static int PARAM_TAG_EXPECTED_ORDER = 0; + public final static int THROWS_TAG_EXPECTED_ORDER = 1; + public final static int SEE_TAG_EXPECTED_ORDER = 2; + + // Kind of comment parser + public final static int COMPIL_PARSER = 0x00000001; + public final static int DOM_PARSER = 0x00000002; + + // Public fields + public Scanner scanner; + public boolean checkDocComment = false; + + // Protected fields + protected boolean inherited, deprecated; + protected char[] source; + protected int index, endComment, lineEnd; + protected int tokenPreviousPosition, lastIdentifierEndPosition, starPosition; + protected int textStart, memberStart; + protected int tagSourceStart, tagSourceEnd; + protected int inlineTagStart; + protected Parser sourceParser; + protected Object returnStatement; + protected boolean lineStarted = false, inlineTagStarted = false; + protected int kind; + protected int[] lineEnds; + + // Private fields + private int currentTokenType = -1; + + // Line pointers + private int linePtr, lastLinePtr; + + // Identifier stack + protected int identifierPtr; + protected char[][] identifierStack; + protected int identifierLengthPtr; + protected int[] identifierLengthStack; + protected long[] identifierPositionStack; + // Ast stack + protected static int AstStackIncrement = 10; + protected int astPtr; + protected Object[] astStack; + protected int astLengthPtr; + protected int[] astLengthStack; + + protected AbstractCommentParser(Parser sourceParser) { + this.sourceParser = sourceParser; + this.scanner = new Scanner(false, false, false, ClassFileConstants.JDK1_3, null, null, true/*taskCaseSensitive*/); + this.identifierStack = new char[20][]; + this.identifierPositionStack = new long[20]; + this.identifierLengthStack = new int[10]; + this.astStack = new Object[30]; + this.astLengthStack = new int[20]; + } + + /* (non-Javadoc) + * Returns true if tag @deprecated is present in javadoc comment. + * + * If javadoc checking is enabled, will also construct an Javadoc node, which will be stored into Parser.javadoc + * slot for being consumed later on. + */ + protected boolean parseComment(int javadocStart, int javadocEnd) { + + boolean validComment = true; + try { + // Init scanner position + this.scanner.resetTo(javadocStart, javadocEnd); + this.endComment = javadocEnd; + this.index = javadocStart; + readChar(); // starting '/' + int previousPosition = this.index; + readChar(); // first '*' + char nextCharacter= readChar(); // second '*' + + // Init local variables + this.astLengthPtr = -1; + this.astPtr = -1; + this.currentTokenType = -1; + this.inlineTagStarted = false; + this.inlineTagStart = -1; + this.lineStarted = false; + this.returnStatement = null; + this.inherited = false; + this.deprecated = false; + this.linePtr = getLineNumber(javadocStart); + this.lastLinePtr = getLineNumber(javadocEnd); + this.lineEnd = (this.linePtr == this.lastLinePtr) ? this.endComment : this.scanner.getLineEnd(this.linePtr); + this.textStart = -1; + char previousChar = 0; + int invalidTagLineEnd = -1; + int invalidInlineTagLineEnd = -1; + + // Loop on each comment character + while (this.index < this.endComment) { + previousPosition = this.index; + previousChar = nextCharacter; + + // Calculate line end (cannot use this.scanner.linePtr as scanner does not parse line ends again) + if (this.index > (this.lineEnd+1)) { + updateLineEnd(); + } + + // Read next char only if token was consumed + if (this.currentTokenType < 0) { + nextCharacter = readChar(); // consider unicodes + } else { + previousPosition = this.scanner.getCurrentTokenStartPosition(); + switch (this.currentTokenType) { + case TerminalTokens.TokenNameRBRACE: + nextCharacter = '}'; + break; + case TerminalTokens.TokenNameMULTIPLY: + nextCharacter = '*'; + break; + default: + nextCharacter = this.scanner.currentCharacter; + } + consumeToken(); + } + + if (this.index >= this.endComment) { + break; + } + + switch (nextCharacter) { + case '@' : + boolean valid = false; + // Start tag parsing only if we have a java identifier start character and if we are on line beginning or at inline tag beginning + if ((!this.lineStarted || previousChar == '{')) { + this.lineStarted = true; + if (this.inlineTagStarted) { + this.inlineTagStarted = false; + // bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=53279 + // Cannot have @ inside inline comment + if (this.sourceParser != null) { + int end = previousPosition, * chars and spaces are not allowed in tag names + switch (pc) { + case '}': + case '!': + case '#': + case '%': + case '&': + case '\'': + case ':': + // case '-': allowed in tag names as this character is often used in doclets (bug 68087) + case '<': + case '>': + case '*': // break for '*' as this is perhaps the end of comment (bug 65288) + break tagNameToken; + default: + if (pc == ' ' || Character.isWhitespace(pc)) break tagNameToken; + } + tk = readTokenAndConsume(); + pc = peekChar(); + } + int length = this.tagSourceEnd-this.tagSourceStart+1; + tag = new char[length]; + System.arraycopy(this.source, this.tagSourceStart, tag, 0, length); + this.index = this.tagSourceEnd+1; + this.scanner.currentPosition = this.tagSourceEnd+1; + this.tagSourceStart = previousPosition; + this.lineEnd = le; + } + switch (token) { + case TerminalTokens.TokenNameIdentifier : + if (CharOperation.equals(tag, TAG_DEPRECATED)) { + this.deprecated = true; + if (this.kind == DOM_PARSER) { + valid = parseTag(); + } else { + valid = true; + } + } else if (CharOperation.equals(tag, TAG_INHERITDOC)) { + // inhibits inherited flag when tags have been already stored + // see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=51606 + // Note that for DOM_PARSER, nodes stack may be not empty even no '@' tag + // was encountered in comment. But it cannot be the case for COMPILER_PARSER + // and so is enough as it is only this parser which signals the missing tag warnings... + this.inherited = this.astPtr==-1; + if (this.kind == DOM_PARSER) { + valid = parseTag(); + } else { + valid = true; + } + } else if (CharOperation.equals(tag, TAG_PARAM)) { + valid = parseParam(); + } else if (CharOperation.equals(tag, TAG_EXCEPTION)) { + valid = parseThrows(false); + } else if (CharOperation.equals(tag, TAG_SEE)) { + if (this.inlineTagStarted) { + // bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=53290 + // Cannot have @see inside inline comment + valid = false; + if (this.sourceParser != null) + this.sourceParser.problemReporter().javadocUnexpectedTag(this.tagSourceStart, this.tagSourceEnd); + } else { + valid = parseSee(false); + } + } else if (CharOperation.equals(tag, TAG_LINK)) { + if (this.inlineTagStarted) { + valid = parseSee(false); + } else { + // bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=53290 + // Cannot have @link outside inline comment + valid = false; + if (this.sourceParser != null) + this.sourceParser.problemReporter().javadocUnexpectedTag(this.tagSourceStart, this.tagSourceEnd); + } + } else if (CharOperation.equals(tag, TAG_LINKPLAIN)) { + if (this.inlineTagStarted) { + valid = parseSee(true); + } else { + valid = parseTag(); + } + } else { + valid = parseTag(); + } + break; + case TerminalTokens.TokenNamereturn : + valid = parseReturn(); + // verify characters after return tag (we're expecting text description) + if(!verifyCharsAfterReturnTag(this.index)) { + if (this.sourceParser != null) { + int end = this.starPosition == -1 || this.lineEnd= this.endComment) end = invalidInlineTagLineEnd; + this.sourceParser.problemReporter().javadocUnterminatedInlineTag(this.inlineTagStart, end); + } + if (this.lineStarted && this.textStart != -1 && this.textStart < previousPosition) { + pushText(this.textStart, previousPosition); + } + if (this.kind == DOM_PARSER) { + refreshInlineTagPosition(previousPosition); + } + } else if (this.lineStarted && this.textStart < previousPosition) { + pushText(this.textStart, previousPosition); + } + updateDocComment(); + } catch (Exception ex) { + validComment = false; + } + return validComment; + } + + private void consumeToken() { + this.currentTokenType = -1; // flush token cache + updateLineEnd(); + } + + protected abstract Object createArgumentReference(char[] name, int dim, Object typeRef, long[] dimPos, long argNamePos) throws InvalidInputException; + protected abstract Object createFieldReference(Object receiver) throws InvalidInputException; + protected abstract Object createMethodReference(Object receiver, List arguments) throws InvalidInputException; + protected Object createReturnStatement() { return null; } + protected abstract Object createTypeReference(int primitiveToken); + + private int getEndPosition() { + if (this.scanner.getCurrentTokenEndPosition() > this.lineEnd) { + return this.lineEnd; + } else { + return this.scanner.getCurrentTokenEndPosition(); + } + } + + /* + * Search the source position corresponding to the end of a given line number. + * Warning: returned position is 1-based index! + * @see Scanner#getLineEnd(int) We cannot directly use this method + * when linePtr field is not initialized. + * + private int getLineEnd(int lineNumber) { + + if (this.scanner.linePtr != -1) { + return this.scanner.getLineEnd(lineNumber); + } + if (this.lineEnds == null) + return -1; + if (lineNumber > this.lineEnds.length+1) + return -1; + if (lineNumber <= 0) + return -1; + if (lineNumber == this.lineEnds.length + 1) + return this.scanner.eofPosition; + return this.lineEnds[lineNumber-1]; // next line start one character behind the lineEnd of the previous line + } + */ + + /** + * Search the line number corresponding to a specific position. + * Warning: returned position is 1-based index! + * @see Scanner#getLineNumber(int) We cannot directly use this method + * when linePtr field is not initialized. + */ + private int getLineNumber(int position) { + + if (this.scanner.linePtr != -1) { + return this.scanner.getLineNumber(position); + } + if (this.lineEnds == null) + return 1; + int length = this.lineEnds.length; + if (length == 0) + return 1; + int g = 0, d = length - 1; + int m = 0; + while (g <= d) { + m = (g + d) /2; + if (position < this.lineEnds[m]) { + d = m-1; + } else if (position > this.lineEnds[m]) { + g = m+1; + } else { + return m + 1; + } + } + if (position < this.lineEnds[m]) { + return m+1; + } + return m+2; + } + + /* + * Parse argument in @see tag method reference + */ + private Object parseArguments(Object receiver) throws InvalidInputException { + + // Init + int modulo = 0; // should be 2 for (Type,Type,...) or 3 for (Type arg,Type arg,...) + int iToken = 0; + char[] argName = null; + List arguments = new ArrayList(10); + int start = this.scanner.getCurrentTokenStartPosition(); + + // Parse arguments declaration if method reference + nextArg : while (this.index < this.scanner.eofPosition) { + + // Read argument type reference + Object typeRef; + try { + typeRef = parseQualifiedName(false); + } catch (InvalidInputException e) { + break nextArg; + } + boolean firstArg = modulo == 0; + if (firstArg) { // verify position + if (iToken != 0) + break nextArg; + } else if ((iToken % modulo) != 0) { + break nextArg; + } + if (typeRef == null) { + if (firstArg && this.currentTokenType == TerminalTokens.TokenNameRPAREN) { + // verify characters after arguments declaration (expecting white space or end comment) + if (!verifySpaceOrEndComment()) { + int end = this.starPosition == -1 ? this.lineEnd : this.starPosition; + if (this.source[end]=='\n') end--; + if (this.sourceParser != null) this.sourceParser.problemReporter().javadocMalformedSeeReference(start, end); + return null; + } + this.lineStarted = true; + return createMethodReference(receiver, null); + } + break nextArg; + } + iToken++; + + // Read possible array declaration + int dim = 0; + long[] dimPositions = new long[20]; // assume that there won't be more than 20 dimensions... + if (readToken() == TerminalTokens.TokenNameLBRACKET) { + int dimStart = this.scanner.getCurrentTokenStartPosition(); + while (readToken() == TerminalTokens.TokenNameLBRACKET) { + consumeToken(); + if (readToken() != TerminalTokens.TokenNameRBRACKET) { + break nextArg; + } + consumeToken(); + dimPositions[dim++] = (((long) dimStart) << 32) + this.scanner.getCurrentTokenEndPosition(); + } + } + + // Read argument name + long argNamePos = -1; + if (readToken() == TerminalTokens.TokenNameIdentifier) { + consumeToken(); + if (firstArg) { // verify position + if (iToken != 1) + break nextArg; + } else if ((iToken % modulo) != 1) { + break nextArg; + } + if (argName == null) { // verify that all arguments name are declared + if (!firstArg) { + break nextArg; + } + } + argName = this.scanner.getCurrentIdentifierSource(); + argNamePos = (((long)this.scanner.getCurrentTokenStartPosition())<<32)+this.scanner.getCurrentTokenEndPosition(); + iToken++; + } else if (argName != null) { // verify that no argument name is declared + break nextArg; + } + + // Verify token position + if (firstArg) { + modulo = iToken + 1; + } else { + if ((iToken % modulo) != (modulo - 1)) { + break nextArg; + } + } + + // Read separator or end arguments declaration + int token = readToken(); + char[] name = argName == null ? new char[0] : argName; + if (token == TerminalTokens.TokenNameCOMMA) { + // Create new argument + Object argument = createArgumentReference(name, dim, typeRef, dimPositions, argNamePos); + arguments.add(argument); + consumeToken(); + iToken++; + } else if (token == TerminalTokens.TokenNameRPAREN) { + // verify characters after arguments declaration (expecting white space or end comment) + if (!verifySpaceOrEndComment()) { + int end = this.starPosition == -1 ? this.lineEnd : this.starPosition; + if (this.source[end]=='\n') end--; + if (this.sourceParser != null) this.sourceParser.problemReporter().javadocMalformedSeeReference(start, end); + return null; + } + // Create new argument + Object argument = createArgumentReference(name, dim, typeRef, dimPositions, argNamePos); + arguments.add(argument); + consumeToken(); + return createMethodReference(receiver, arguments); + } else { + break nextArg; + } + } + + // Something wrong happened => Invalid input + throw new InvalidInputException(); + } + + /* + * Parse an URL link reference in @see tag + */ + private boolean parseHref() throws InvalidInputException { + int start = this.scanner.getCurrentTokenStartPosition(); + if (Character.toLowerCase(readChar()) == 'a') { + this.scanner.currentPosition = this.index; + if (readToken() == TerminalTokens.TokenNameIdentifier) { + this.currentTokenType = -1; // do not update line end + try { + if (CharOperation.equals(this.scanner.getCurrentIdentifierSource(), new char[]{'h', 'r', 'e', 'f'}, false) && + readToken() == TerminalTokens.TokenNameEQUAL) { + this.currentTokenType = -1; // do not update line end + if (readToken() == TerminalTokens.TokenNameStringLiteral) { + this.currentTokenType = -1; // do not update line end + // Skip all characters after string literal until closing '>' (see bug 68726) + while (this.index <= this.lineEnd && readToken() != TerminalTokens.TokenNameGREATER) { + this.currentTokenType = -1; // do not update line end + } + if (this.currentTokenType == TerminalTokens.TokenNameGREATER) { + consumeToken(); // update line end as new lines are allowed in URL description + while (readToken() != TerminalTokens.TokenNameLESS) { + if (this.scanner.currentPosition >= this.scanner.eofPosition || this.scanner.currentCharacter == '@') { + // Reset position: we want to rescan last token + this.index = this.tokenPreviousPosition; + this.scanner.currentPosition = this.tokenPreviousPosition; + this.currentTokenType = -1; + // Signal syntax error + if (this.sourceParser != null) this.sourceParser.problemReporter().javadocInvalidSeeUrlReference(start, this.lineEnd); + return false; + } + consumeToken(); + } + this.currentTokenType = -1; // do not update line end + if (readChar() == '/') { + if (Character.toLowerCase(readChar()) == 'a') { + if (readChar() == '>') { + // Valid href + return true; + } + } + } + } + } + } + } catch (InvalidInputException ex) { + // Do nothing as we want to keep positions for error message + } + } + } + // Reset position: we want to rescan last token + this.index = this.tokenPreviousPosition; + this.scanner.currentPosition = this.tokenPreviousPosition; + this.currentTokenType = -1; + // Signal syntax error + if (this.sourceParser != null) this.sourceParser.problemReporter().javadocInvalidSeeUrlReference(start, this.lineEnd); + return false; + } + + /* + * Parse a method reference in @see tag + */ + private Object parseMember(Object receiver) throws InvalidInputException { + // Init + this.identifierPtr = -1; + this.identifierLengthPtr = -1; + int start = this.scanner.getCurrentTokenStartPosition(); + this.memberStart = start; + + // Get member identifier + if (readToken() == TerminalTokens.TokenNameIdentifier) { + consumeToken(); + pushIdentifier(true); + // Look for next token to know whether it's a field or method reference + int previousPosition = this.index; + if (readToken() == TerminalTokens.TokenNameLPAREN) { + consumeToken(); + start = this.scanner.getCurrentTokenStartPosition(); + try { + return parseArguments(receiver); + } catch (InvalidInputException e) { + int end = this.scanner.getCurrentTokenEndPosition() < this.lineEnd ? + this.scanner.getCurrentTokenEndPosition() : + this.scanner.getCurrentTokenStartPosition(); + end = end < this.lineEnd ? end : this.lineEnd; + if (this.sourceParser != null) this.sourceParser.problemReporter().javadocInvalidSeeReferenceArgs(start, end); + } + return null; + } + + // Reset position: we want to rescan last token + this.index = previousPosition; + this.scanner.currentPosition = previousPosition; + this.currentTokenType = -1; + + // Verify character(s) after identifier (expecting space or end comment) + if (!verifySpaceOrEndComment()) { + int end = this.starPosition == -1 ? this.lineEnd : this.starPosition; + if (this.source[end]=='\n') end--; + if (this.sourceParser != null) this.sourceParser.problemReporter().javadocMalformedSeeReference(start, end); + return null; + } + return createFieldReference(receiver); + } + int end = getEndPosition() - 1; + end = start > end ? start : end; + if (this.sourceParser != null) this.sourceParser.problemReporter().javadocInvalidSeeReference(start, end); + // Reset position: we want to rescan last token + this.index = this.tokenPreviousPosition; + this.scanner.currentPosition = this.tokenPreviousPosition; + this.currentTokenType = -1; + return null; + } + + /* + * Parse @param tag declaration + */ + protected boolean parseParam() { + + // Store current token state + int start = this.tagSourceStart; + int end = this.tagSourceEnd; + + try { + // Push identifier next + int token = readToken(); + switch (token) { + case TerminalTokens.TokenNameIdentifier : + consumeToken(); + return pushParamName(); + case TerminalTokens.TokenNameEOF : + break; + default : + start = this.scanner.getCurrentTokenStartPosition(); + end = getEndPosition(); + if (end < start) start = this.tagSourceStart; + break; + } + } catch (InvalidInputException e) { + end = getEndPosition(); + } + + // Reset position to avoid missing tokens when new line was encountered + this.index = this.tokenPreviousPosition; + this.scanner.currentPosition = this.tokenPreviousPosition; + this.currentTokenType = -1; + + // Report problem + if (this.sourceParser != null) this.sourceParser.problemReporter().javadocMissingParamName(start, end); + return false; + } + + /* + * Parse a qualified name and built a type reference if the syntax is valid. + */ + protected Object parseQualifiedName(boolean reset) throws InvalidInputException { + + // Reset identifier stack if requested + if (reset) { + this.identifierPtr = -1; + this.identifierLengthPtr = -1; + } + + // Scan tokens + int primitiveToken = -1; + nextToken : for (int iToken = 0; ; iToken++) { + int token = readToken(); + switch (token) { + case TerminalTokens.TokenNameIdentifier : + if (((iToken % 2) > 0)) { // identifiers must be odd tokens + break nextToken; + } + pushIdentifier(iToken == 0); + consumeToken(); + break; + + case TerminalTokens.TokenNameDOT : + if ((iToken % 2) == 0) { // dots must be even tokens + throw new InvalidInputException(); + } + consumeToken(); + break; + + case TerminalTokens.TokenNamevoid : + case TerminalTokens.TokenNameboolean : + case TerminalTokens.TokenNamebyte : + case TerminalTokens.TokenNamechar : + case TerminalTokens.TokenNamedouble : + case TerminalTokens.TokenNamefloat : + case TerminalTokens.TokenNameint : + case TerminalTokens.TokenNamelong : + case TerminalTokens.TokenNameshort : + if (iToken > 0) { + throw new InvalidInputException(); + } + pushIdentifier(true); + primitiveToken = token; + consumeToken(); + break nextToken; + + default : + if (iToken == 0) { + return null; + } + if ((iToken % 2) == 0) { // cannot leave on a dot + // Reset position: we want to rescan last token + if (this.kind == DOM_PARSER && this.currentTokenType != -1) { + this.index = this.tokenPreviousPosition; + this.scanner.currentPosition = this.tokenPreviousPosition; + this.currentTokenType = -1; + } + throw new InvalidInputException(); + } + break nextToken; + } + } + // Reset position: we want to rescan last token + if (this.currentTokenType != -1) { + this.index = this.tokenPreviousPosition; + this.scanner.currentPosition = this.tokenPreviousPosition; + this.currentTokenType = -1; + } + this.lastIdentifierEndPosition = (int) this.identifierPositionStack[this.identifierPtr]; + return createTypeReference(primitiveToken); + } + + /* + * Parse a reference in @see tag + */ + protected boolean parseReference(boolean plain) throws InvalidInputException { + Object typeRef = null; + Object reference = null; + int previousPosition = -1; + int typeRefStartPosition = -1; + nextToken : while (this.index < this.scanner.eofPosition) { + previousPosition = this.index; + int token = readToken(); + switch (token) { + case TerminalTokens.TokenNameStringLiteral : // @see "string" + int start = this.scanner.getCurrentTokenStartPosition(); + consumeToken(); + // If typeRef != null we may raise a warning here to let user know there's an unused reference... + // Currently as javadoc 1.4.2 ignore it, we do the same (see bug 69302) + if (typeRef != null) { + start = this.tagSourceEnd+1; + previousPosition = start; + typeRef = null; + } + // verify end line (expecting empty or end comment) + if (verifyEndLine(previousPosition)) { + return true; + } + if (this.sourceParser != null) this.sourceParser.problemReporter().javadocInvalidSeeReference(start, this.lineEnd); + return false; + case TerminalTokens.TokenNameLESS : // @see "label + consumeToken(); + start = this.scanner.getCurrentTokenStartPosition(); + if (parseHref()) { + consumeToken(); + // If typeRef != null we may raise a warning here to let user know there's an unused reference... + // Currently as javadoc 1.4.2 ignore it, we do the same (see bug 69302) + if (typeRef != null) { + start = this.tagSourceEnd+1; + previousPosition = start; + typeRef = null; + } + // verify end line (expecting empty or end comment) + if (verifyEndLine(previousPosition)) { + return true; + } + if (this.sourceParser != null) this.sourceParser.problemReporter().javadocInvalidSeeReference(start, this.lineEnd); + } + return false; + case TerminalTokens.TokenNameERROR : + if (this.scanner.currentCharacter == '#') { // @see ...#member + consumeToken(); + reference = parseMember(typeRef); + if (reference != null) { + return pushSeeRef(reference, plain); + } + return false; + } + break nextToken; + case TerminalTokens.TokenNameIdentifier : + if (typeRef == null) { + typeRefStartPosition = this.scanner.getCurrentTokenStartPosition(); + typeRef = parseQualifiedName(true); + break; + } + break nextToken; + default : + break nextToken; + } + } + + // Verify that we got a reference + if (reference == null) reference = typeRef; + if (reference == null) { + this.index = this.tokenPreviousPosition; + this.scanner.currentPosition = this.tokenPreviousPosition; + this.currentTokenType = -1; + if (this.sourceParser != null) this.sourceParser.problemReporter().javadocMissingSeeReference(this.tagSourceStart, this.tagSourceEnd); + return false; + } + + // Reset position at the end of type reference + this.index = this.lastIdentifierEndPosition+1; + this.scanner.currentPosition = this.index; + this.currentTokenType = -1; + + // Verify that line end does not start with an open parenthese (which could be a constructor reference wrongly written...) + // See bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=47215 + char ch = peekChar(); + if (ch == '(') { + if (this.sourceParser != null) this.sourceParser.problemReporter().javadocInvalidSeeReference(typeRefStartPosition, this.lineEnd); + return false; + } + + // Verify that we get white space after reference + if (!verifySpaceOrEndComment()) { + this.index = this.tokenPreviousPosition; + this.scanner.currentPosition = this.tokenPreviousPosition; + this.currentTokenType = -1; + int end = this.starPosition == -1 ? this.lineEnd : this.starPosition; + if (this.source[end]=='\n') end--; + if (this.sourceParser != null) this.sourceParser.problemReporter().javadocMalformedSeeReference(typeRefStartPosition, end); + return false; + } + + // Everything is OK, store reference + return pushSeeRef(reference, plain); + } + + /* + * Parse @return tag declaration + */ + protected abstract boolean parseReturn(); + + /* + * Parse @see tag declaration + */ + protected boolean parseSee(boolean plain) { + int start = this.scanner.currentPosition; + try { + return parseReference(plain); + } catch (InvalidInputException ex) { + if (this.sourceParser != null) this.sourceParser.problemReporter().javadocInvalidSeeReference(start, getEndPosition()); + } + // Reset position to avoid missing tokens when new line was encountered + this.index = this.tokenPreviousPosition; + this.scanner.currentPosition = this.tokenPreviousPosition; + this.currentTokenType = -1; + return false; + } + + /* + * Parse @return tag declaration + */ + protected abstract boolean parseTag(); + + /* + * Parse @throws tag declaration + */ + protected boolean parseThrows(boolean real) { + int start = this.scanner.currentPosition; + try { + Object typeRef = parseQualifiedName(true); + if (typeRef == null) { + if (this.sourceParser != null) this.sourceParser.problemReporter().javadocMissingThrowsClassName(this.tagSourceStart, this.tagSourceEnd); + } else { + return pushThrowName(typeRef, real); + } + } catch (InvalidInputException ex) { + if (this.sourceParser != null) this.sourceParser.problemReporter().javadocInvalidThrowsClass(start, getEndPosition()); + } + return false; + } + + /* + * Return current character without move index position. + */ + private char peekChar() { + int idx = this.index; + char c = this.source[idx++]; + if (c == '\\' && this.source[idx] == 'u') { + int c1, c2, c3, c4; + idx++; + while (this.source[idx] == 'u') + idx++; + if (!(((c1 = Character.getNumericValue(this.source[idx++])) > 15 || c1 < 0) + || ((c2 = Character.getNumericValue(this.source[idx++])) > 15 || c2 < 0) + || ((c3 = Character.getNumericValue(this.source[idx++])) > 15 || c3 < 0) || ((c4 = Character.getNumericValue(this.source[idx++])) > 15 || c4 < 0))) { + c = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + } + } + return c; + } + + /* + * push the consumeToken on the identifier stack. Increase the total number of identifier in the stack. + */ + protected void pushIdentifier(boolean newLength) { + + int stackLength = this.identifierStack.length; + if (++this.identifierPtr >= stackLength) { + System.arraycopy( + this.identifierStack, 0, + this.identifierStack = new char[stackLength + 10][], 0, + stackLength); + System.arraycopy( + this.identifierPositionStack, 0, + this.identifierPositionStack = new long[stackLength + 10], 0, + stackLength); + } + this.identifierStack[this.identifierPtr] = this.scanner.getCurrentIdentifierSource(); + this.identifierPositionStack[this.identifierPtr] = (((long) this.scanner.startPosition) << 32) + (this.scanner.currentPosition - 1); + + if (newLength) { + stackLength = this.identifierLengthStack.length; + if (++this.identifierLengthPtr >= stackLength) { + System.arraycopy( + this.identifierLengthStack, 0, + this.identifierLengthStack = new int[stackLength + 10], 0, + stackLength); + } + this.identifierLengthStack[this.identifierLengthPtr] = 1; + } else { + this.identifierLengthStack[this.identifierLengthPtr]++; + } + } + + /* + * Add a new obj on top of the ast stack. + * If new length is required, then add also a new length in length stack. + */ + protected void pushOnAstStack(Object node, boolean newLength) { + + if (node == null) { + this.astLengthStack[++this.astLengthPtr] = 0; + return; + } + + int stackLength = this.astStack.length; + if (++this.astPtr >= stackLength) { + System.arraycopy( + this.astStack, 0, + this.astStack = new Object[stackLength + AstStackIncrement], 0, + stackLength); + this.astPtr = stackLength; + } + this.astStack[this.astPtr] = node; + + if (newLength) { + stackLength = this.astLengthStack.length; + if (++this.astLengthPtr >= stackLength) { + System.arraycopy( + this.astLengthStack, 0, + this.astLengthStack = new int[stackLength + AstStackIncrement], 0, + stackLength); + } + this.astLengthStack[this.astLengthPtr] = 1; + } else { + this.astLengthStack[this.astLengthPtr]++; + } + } + + /* + * Push a param name in ast node stack. + */ + protected abstract boolean pushParamName(); + + /* + * Push a reference statement in ast node stack. + */ + protected abstract boolean pushSeeRef(Object statement, boolean plain); + + /* + * Push a text element in ast node stack + */ + protected abstract void pushText(int start, int end); + + /* + * Push a throws type ref in ast node stack. + */ + protected abstract boolean pushThrowName(Object typeRef, boolean real); + + /* + * Read current character and move index position. + * Warning: scanner position is unchanged using this method! + */ + protected char readChar() { + + char c = this.source[this.index++]; + if (c == '\\' && this.source[this.index] == 'u') { + int c1, c2, c3, c4; + int pos = this.index; + this.index++; + while (this.source[this.index] == 'u') + this.index++; + if (!(((c1 = Character.getNumericValue(this.source[this.index++])) > 15 || c1 < 0) + || ((c2 = Character.getNumericValue(this.source[this.index++])) > 15 || c2 < 0) + || ((c3 = Character.getNumericValue(this.source[this.index++])) > 15 || c3 < 0) || ((c4 = Character.getNumericValue(this.source[this.index++])) > 15 || c4 < 0))) { + c = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + } else { + // TODO (frederic) currently reset to previous position, perhaps signal a syntax error would be more appropriate + this.index = pos; + } + } + return c; + } + + /* + * Read token only if previous was consumed + */ + private int readToken() throws InvalidInputException { + if (this.currentTokenType < 0) { + this.tokenPreviousPosition = this.scanner.currentPosition; + this.currentTokenType = this.scanner.getNextToken(); + if (this.scanner.currentPosition > (this.lineEnd+1)) { // be sure to be on next line (lineEnd is still on the same line) + this.lineStarted = false; + while (this.currentTokenType == TerminalTokens.TokenNameMULTIPLY) { + this.currentTokenType = this.scanner.getNextToken(); + } + } + this.index = this.scanner.currentPosition; + this.lineStarted = true; // after having read a token, line is obviously started... + } + return this.currentTokenType; + } + + private int readTokenAndConsume() throws InvalidInputException { + int token = readToken(); + consumeToken(); + return token; + } + + /* + * Refresh start position and length of an inline tag. + */ + protected void refreshInlineTagPosition(int previousPosition) { + // do nothing by default + } + + public String toString() { + StringBuffer buffer = new StringBuffer(); + int startPos = this.scanner.currentPosition this.source.length) + return "behind the EOF\n\n" + new String(this.source); //$NON-NLS-1$ + + char front[] = new char[startPos]; + System.arraycopy(this.source, 0, front, 0, startPos); + + int middleLength = (endPos - 1) - startPos + 1; + char middle[]; + if (middleLength > -1) { + middle = new char[middleLength]; + System.arraycopy( + this.source, + startPos, + middle, + 0, + middleLength); + } else { + middle = CharOperation.NO_CHAR; + } + + char end[] = new char[this.source.length - (endPos - 1)]; + System.arraycopy( + this.source, + (endPos - 1) + 1, + end, + 0, + this.source.length - (endPos - 1) - 1); + + buffer.append(front); + if (this.scanner.currentPosition"); //$NON-NLS-1$ + } else { + buffer.append("\n===============================\nParser index here -->"); //$NON-NLS-1$ + } + buffer.append(middle); + if (this.scanner.currentPosition (this.lineEnd+1)) { // be sure to be on next line (lineEnd is still on the same line) + if (this.linePtr < this.lastLinePtr) { + this.lineEnd = this.scanner.getLineEnd(++this.linePtr) - 1; + } else { + this.lineEnd = this.endComment; + return; + } + } + } + + /* + * Verify that end of the line only contains space characters or end of comment. + * Note that end of comment may be preceeding by several contiguous '*' chars. + */ + private boolean verifyEndLine(int textPosition) { + int startPosition = this.index; + int previousPosition = this.index; + this.starPosition = -1; + char ch = readChar(); + nextChar: while (true) { + switch (ch) { + case '\r': + case '\n': + if (this.kind == DOM_PARSER) { + parseTag(); + pushText(textPosition, previousPosition); + } + this.index = previousPosition; + return true; + case '\u000c' : /* FORM FEED */ + case ' ' : /* SPACE */ + case '\t' : /* HORIZONTAL TABULATION */ + if (this.starPosition >= 0) break nextChar; + break; + case '*': + this.starPosition = previousPosition; + break; + case '/': + if (this.starPosition >= textPosition) { + if (this.kind == DOM_PARSER) { + parseTag(); + pushText(textPosition, this.starPosition); + } + return true; + } + default : + // leave loop + break nextChar; + + } + previousPosition = this.index; + ch = readChar(); + } + this.index = startPosition; + return false; + } + + /* + * Verify that some text exists after a @return tag. Text must be different than + * end of comment which may be preceeding by several '*' chars. + */ + private boolean verifyCharsAfterReturnTag(int startPosition) { + // Whitespace or inline tag closing brace + int previousPosition = this.index; + char ch = readChar(); + boolean malformed = true; + while (Character.isWhitespace(ch)) { + malformed = false; + previousPosition = this.index; + ch = readChar(); + } + // End of comment + this.starPosition = -1; + nextChar: while (this.index= startPosition) { // valid only if a star was previous character + return false; + } + default : + // valid if any other character is encountered, even white spaces + this.index = startPosition; + return !malformed; + + } + previousPosition = this.index; + ch = readChar(); + } + this.index = startPosition; + return false; + } + + /* + * Verify characters after a name matches one of following conditions: + * 1- first character is a white space + * 2- first character is a closing brace *and* we're currently parsing an inline tag + * 3- are the end of comment (several contiguous star ('*') characters may be + * found before the last slash ('/') character). + */ + private boolean verifySpaceOrEndComment() { + int startPosition = this.index; + // Whitespace or inline tag closing brace + char ch = peekChar(); + switch (ch) { + case '}': + return this.inlineTagStarted; + default: + if (Character.isWhitespace(ch)) { + return true; + } + } + // End of comment + int previousPosition = this.index; + this.starPosition = -1; + ch = readChar(); + nextChar: while (this.index= startPosition) { // valid only if a star was previous character + return true; + } + default : + // invalid whatever other character, even white spaces + this.index = startPosition; + return false; + + } + previousPosition = this.index; + ch = readChar(); + } + this.index = startPosition; + return false; + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/JavadocParser.java b/src/java/org/eclipse/jdt/internal/compiler/parser/JavadocParser.java new file mode 100644 index 0000000..7786636 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/parser/JavadocParser.java @@ -0,0 +1,466 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.parser; + +import java.util.List; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.core.compiler.InvalidInputException; +import org.eclipse.jdt.internal.compiler.ast.Expression; +import org.eclipse.jdt.internal.compiler.ast.ImplicitDocTypeReference; +import org.eclipse.jdt.internal.compiler.ast.Javadoc; +import org.eclipse.jdt.internal.compiler.ast.JavadocAllocationExpression; +import org.eclipse.jdt.internal.compiler.ast.JavadocArgumentExpression; +import org.eclipse.jdt.internal.compiler.ast.JavadocArrayQualifiedTypeReference; +import org.eclipse.jdt.internal.compiler.ast.JavadocArraySingleTypeReference; +import org.eclipse.jdt.internal.compiler.ast.JavadocFieldReference; +import org.eclipse.jdt.internal.compiler.ast.JavadocMessageSend; +import org.eclipse.jdt.internal.compiler.ast.JavadocQualifiedTypeReference; +import org.eclipse.jdt.internal.compiler.ast.JavadocReturnStatement; +import org.eclipse.jdt.internal.compiler.ast.JavadocSingleNameReference; +import org.eclipse.jdt.internal.compiler.ast.JavadocSingleTypeReference; +import org.eclipse.jdt.internal.compiler.ast.TypeReference; +import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; +import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; + +/** + * Parser specialized for decoding javadoc comments + */ +public class JavadocParser extends AbstractCommentParser { + + // Public fields + public Javadoc docComment; + + // bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=51600 + // Store param references for tag with invalid syntax + private int invParamsPtr = -1; + private JavadocSingleNameReference[] invParamsStack; + + JavadocParser(Parser sourceParser) { + super(sourceParser); + this.checkDocComment = this.sourceParser.options.docCommentSupport; + this.kind = COMPIL_PARSER; + } + + /* (non-Javadoc) + * Returns true if tag @deprecated is present in javadoc comment. + * + * If javadoc checking is enabled, will also construct an Javadoc node, which will be stored into Parser.javadoc + * slot for being consumed later on. + */ + public boolean checkDeprecation(int javadocStart, int javadocEnd) { + + try { + this.source = this.sourceParser.scanner.source; + this.index = javadocStart +3; + this.endComment = javadocEnd - 2; + if (this.checkDocComment) { + // Initialization + this.scanner.lineEnds = this.sourceParser.scanner.lineEnds; + this.scanner.linePtr = this.sourceParser.scanner.linePtr; + this.lineEnds = this.scanner.lineEnds; + this.docComment = new Javadoc(javadocStart, javadocEnd); + parseComment(javadocStart, javadocEnd); + } else { + // Init javadoc if necessary + if (this.sourceParser.options.getSeverity(CompilerOptions.MissingJavadocComments) != ProblemSeverities.Ignore) { + this.docComment = new Javadoc(javadocStart, javadocEnd); + } else { + this.docComment = null; + } + + // Parse comment + int firstLineNumber = this.sourceParser.scanner.getLineNumber(javadocStart); + int lastLineNumber = this.sourceParser.scanner.getLineNumber(javadocEnd); + + // scan line per line, since tags must be at beginning of lines only + nextLine : for (int line = firstLineNumber; line <= lastLineNumber; line++) { + int lineStart = line == firstLineNumber + ? javadocStart + 3 // skip leading /** + : this.sourceParser.scanner.getLineStart(line); + this.index = lineStart; + this.lineEnd = line == lastLineNumber + ? javadocEnd - 2 // remove trailing * / + : this.sourceParser.scanner.getLineEnd(line); + nextCharacter : while (this.index < this.lineEnd) { + char c = readChar(); // consider unicodes + switch (c) { + default : + if (Character.isWhitespace(c)) { + continue nextCharacter; + } + break; + case '*' : + continue nextCharacter; + case '@' : + if ((readChar() == 'd') && (readChar() == 'e') && + (readChar() == 'p') && (readChar() == 'r') && + (readChar() == 'e') && (readChar() == 'c') && + (readChar() == 'a') && (readChar() == 't') && + (readChar() == 'e') && (readChar() == 'd')) { + // ensure the tag is properly ended: either followed by a space, a tab, line end or asterisk. + c = readChar(); + if (Character.isWhitespace(c) || c == '*') { + return true; + } + } + } + continue nextLine; + } + } + return false; + } + } finally { + this.source = null; // release source as soon as finished + } + return this.deprecated; + } + + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append("check javadoc: ").append(this.checkDocComment).append("\n"); //$NON-NLS-1$ //$NON-NLS-2$ + buffer.append("javadoc: ").append(this.docComment).append("\n"); //$NON-NLS-1$ //$NON-NLS-2$ + buffer.append(super.toString()); + return buffer.toString(); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#createArgumentReference(char[], java.lang.Object, int) + */ + protected Object createArgumentReference(char[] name, int dim, Object typeRef, long[] dimPositions, long argNamePos) throws InvalidInputException { + try { + TypeReference argTypeRef = (TypeReference) typeRef; + if (dim > 0) { + long pos = (((long) argTypeRef.sourceStart) << 32) + argTypeRef.sourceEnd; + if (typeRef instanceof JavadocSingleTypeReference) { + JavadocSingleTypeReference singleRef = (JavadocSingleTypeReference) typeRef; + argTypeRef = new JavadocArraySingleTypeReference(singleRef.token, dim, pos); + } else { + JavadocQualifiedTypeReference qualifRef = (JavadocQualifiedTypeReference) typeRef; + argTypeRef = new JavadocArrayQualifiedTypeReference(qualifRef, dim); + } + } + int argEnd = argTypeRef.sourceEnd; + if (dim > 0) argEnd = (int) dimPositions[dim-1]; + if (argNamePos >= 0) argEnd = (int) argNamePos; + return new JavadocArgumentExpression(name, argTypeRef.sourceStart, argEnd, argTypeRef); + } + catch (ClassCastException ex) { + throw new InvalidInputException(); + } + } + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#createFieldReference() + */ + protected Object createFieldReference(Object receiver) throws InvalidInputException { + try { + // Get receiver type + TypeReference typeRef = (TypeReference) receiver; + if (typeRef == null) { + char[] name = this.sourceParser.compilationUnit.compilationResult.compilationUnit.getMainTypeName(); + typeRef = new ImplicitDocTypeReference(name, this.memberStart); + } + // Create field + JavadocFieldReference field = new JavadocFieldReference(this.identifierStack[0], this.identifierPositionStack[0]); + field.receiver = typeRef; + field.tagSourceStart = this.tagSourceStart; + field.tagSourceEnd = this.tagSourceEnd; + return field; + } + catch (ClassCastException ex) { + throw new InvalidInputException(); + } + } + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#createMethodReference(java.lang.Object[]) + */ + protected Object createMethodReference(Object receiver, List arguments) throws InvalidInputException { + try { + // Get receiver type + TypeReference typeRef = (TypeReference) receiver; + // Decide whether we have a constructor or not + boolean isConstructor = false; + if (typeRef == null) { + char[] name = this.sourceParser.compilationUnit.compilationResult.compilationUnit.getMainTypeName(); + isConstructor = CharOperation.equals(this.identifierStack[0], name); + typeRef = new ImplicitDocTypeReference(name, this.memberStart); + } else { + char[] name = null; + if (typeRef instanceof JavadocSingleTypeReference) { + name = ((JavadocSingleTypeReference)typeRef).token; + } else if (typeRef instanceof JavadocQualifiedTypeReference) { + char[][] tokens = ((JavadocQualifiedTypeReference)typeRef).tokens; + name = tokens[tokens.length-1]; + } else { + throw new InvalidInputException(); + } + isConstructor = CharOperation.equals(this.identifierStack[0], name); + } + // Create node + if (arguments == null) { + if (isConstructor) { + JavadocAllocationExpression expr = new JavadocAllocationExpression(this.identifierPositionStack[0]); + expr.type = typeRef; + return expr; + } else { + JavadocMessageSend msg = new JavadocMessageSend(this.identifierStack[0], this.identifierPositionStack[0]); + msg.receiver = typeRef; + return msg; + } + } else { + JavadocArgumentExpression[] expressions = new JavadocArgumentExpression[arguments.size()]; + arguments.toArray(expressions); + if (isConstructor) { + JavadocAllocationExpression alloc = new JavadocAllocationExpression(this.identifierPositionStack[0]); + alloc.arguments = expressions; + alloc.type = typeRef; + return alloc; + } else { + JavadocMessageSend msg = new JavadocMessageSend(this.identifierStack[0], this.identifierPositionStack[0], expressions); + msg.receiver = typeRef; + return msg; + } + } + } + catch (ClassCastException ex) { + throw new InvalidInputException(); + } + } + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#createReturnStatement() + */ + protected Object createReturnStatement() { + return new JavadocReturnStatement(this.scanner.getCurrentTokenStartPosition(), + this.scanner.getCurrentTokenEndPosition(), + this.scanner.getRawTokenSourceEnd()); + } + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#createTypeReference() + */ + protected Object createTypeReference(int primitiveToken) { + TypeReference typeRef = null; + int size = this.identifierLengthStack[this.identifierLengthPtr--]; + if (size == 1) { // Single Type ref + typeRef = new JavadocSingleTypeReference( + this.identifierStack[this.identifierPtr], + this.identifierPositionStack[this.identifierPtr], + this.tagSourceStart, + this.tagSourceEnd); + } else if (size > 1) { // Qualified Type ref + char[][] tokens = new char[size][]; + System.arraycopy(this.identifierStack, this.identifierPtr - size + 1, tokens, 0, size); + long[] positions = new long[size]; + System.arraycopy(this.identifierPositionStack, this.identifierPtr - size + 1, positions, 0, size); + typeRef = new JavadocQualifiedTypeReference(tokens, positions, this.tagSourceStart, this.tagSourceEnd); + } + this.identifierPtr -= size; + return typeRef; + } + + /* + * Parse @return tag declaration + */ + protected boolean parseReturn() { + if (this.returnStatement == null) { + this.returnStatement = createReturnStatement(); + return true; + } + if (this.sourceParser != null) this.sourceParser.problemReporter().javadocDuplicatedReturnTag( + this.scanner.getCurrentTokenStartPosition(), + this.scanner.getCurrentTokenEndPosition()); + return false; + } + + /* + * Parse @return tag declaration + */ + protected boolean parseTag() { + return true; + } + + /* + * Push a param name in ast node stack. + */ + protected boolean pushParamName() { + // Create name reference + JavadocSingleNameReference nameRef = new JavadocSingleNameReference(this.scanner.getCurrentIdentifierSource(), + this.scanner.getCurrentTokenStartPosition(), + this.scanner.getCurrentTokenEndPosition()); + nameRef.tagSourceStart = this.tagSourceStart; + nameRef.tagSourceEnd = this.tagSourceEnd; + // Push ref on stack + if (this.astLengthPtr == -1) { // First push + pushOnAstStack(nameRef, true); + } else { + // Verify that no @throws has been declared before + for (int i=THROWS_TAG_EXPECTED_ORDER; i<=this.astLengthPtr; i+=ORDERED_TAGS_NUMBER) { + if (this.astLengthStack[i] != 0) { + if (this.sourceParser != null) this.sourceParser.problemReporter().javadocUnexpectedTag(this.tagSourceStart, this.tagSourceEnd); + // bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=51600 + // store param references in specific array + if (this.invParamsPtr == -1l) { + this.invParamsStack = new JavadocSingleNameReference[10]; + } + int stackLength = this.invParamsStack.length; + if (++this.invParamsPtr >= stackLength) { + System.arraycopy( + this.invParamsStack, 0, + this.invParamsStack = new JavadocSingleNameReference[stackLength + AstStackIncrement], 0, + stackLength); + } + this.invParamsStack[this.invParamsPtr] = nameRef; + return false; + } + } + switch (this.astLengthPtr % ORDERED_TAGS_NUMBER) { + case PARAM_TAG_EXPECTED_ORDER : + // previous push was a @param tag => push another param name + pushOnAstStack(nameRef, false); + break; + case SEE_TAG_EXPECTED_ORDER : + // previous push was a @see tag => push new param name + pushOnAstStack(nameRef, true); + break; + default: + return false; + } + } + return true; + } + + /* + * Push a reference statement in ast node stack. + */ + protected boolean pushSeeRef(Object statement, boolean plain) { + if (this.astLengthPtr == -1) { // First push + pushOnAstStack(null, true); + pushOnAstStack(null, true); + pushOnAstStack(statement, true); + } else { + switch (this.astLengthPtr % ORDERED_TAGS_NUMBER) { + case PARAM_TAG_EXPECTED_ORDER : + // previous push was a @param tag => push empty @throws tag and new @see tag + pushOnAstStack(null, true); + pushOnAstStack(statement, true); + break; + case THROWS_TAG_EXPECTED_ORDER : + // previous push was a @throws tag => push new @see tag + pushOnAstStack(statement, true); + break; + case SEE_TAG_EXPECTED_ORDER : + // previous push was a @see tag => push another @see tag + pushOnAstStack(statement, false); + break; + default: + return false; + } + } + return true; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#pushText(int, int) + */ + protected void pushText(int start, int end) { + // compiler does not matter of text + } + + /* + * Push a throws type ref in ast node stack. + */ + protected boolean pushThrowName(Object typeRef, boolean real) { + if (this.astLengthPtr == -1) { // First push + pushOnAstStack(null, true); + pushOnAstStack(typeRef, true); + } else { + switch (this.astLengthPtr % ORDERED_TAGS_NUMBER) { + case PARAM_TAG_EXPECTED_ORDER : + // previous push was a @param tag => push new @throws tag + pushOnAstStack(typeRef, true); + break; + case THROWS_TAG_EXPECTED_ORDER : + // previous push was a @throws tag => push another @throws tag + pushOnAstStack(typeRef, false); + break; + case SEE_TAG_EXPECTED_ORDER : + // previous push was a @see tag => push empty @param and new @throws tags + pushOnAstStack(null, true); + pushOnAstStack(typeRef, true); + break; + default: + return false; + } + } + return true; + } + + /* + * Fill associated comment fields with ast nodes information stored in stack. + */ + protected void updateDocComment() { + + // Set inherited flag + this.docComment.inherited = this.inherited; + + // Set return node if present + if (this.returnStatement != null) { + this.docComment.returnStatement = (JavadocReturnStatement) this.returnStatement; + } + + // Copy array of invalid syntax param tags + if (this.invParamsPtr >= 0) { + this.docComment.invalidParameters = new JavadocSingleNameReference[this.invParamsPtr+1]; + System.arraycopy(this.invParamsStack, 0, this.docComment.invalidParameters, 0, this.invParamsPtr+1); + } + + // If no nodes stored return + if (this.astLengthPtr == -1) { + return; + } + + // Initialize arrays + int[] sizes = new int[ORDERED_TAGS_NUMBER]; + for (int i=0; i<=this.astLengthPtr; i++) { + sizes[i%ORDERED_TAGS_NUMBER] += this.astLengthStack[i]; + } + this.docComment.references = new Expression[sizes[SEE_TAG_EXPECTED_ORDER]]; + this.docComment.thrownExceptions = new TypeReference[sizes[THROWS_TAG_EXPECTED_ORDER]]; + this.docComment.parameters = new JavadocSingleNameReference[sizes[PARAM_TAG_EXPECTED_ORDER]]; + + // Store nodes in arrays + while (this.astLengthPtr >= 0) { + int ptr = this.astLengthPtr % ORDERED_TAGS_NUMBER; + // Starting with the stack top, so get references (eg. Expression) coming from @see declarations + if (ptr == SEE_TAG_EXPECTED_ORDER) { + int size = this.astLengthStack[this.astLengthPtr--]; + for (int i=0; i= 0 && index < this.elements.size(); + } + + public int size(){ + return this.elements.size(); + } + + public String toString() { + StringBuffer result= new StringBuffer(); + for (Iterator iter= iterator(); iter.hasNext(); ) { + result.append("\t"); //$NON-NLS-1$ + result.append(iter.next().toString()); + result.append("\n"); //$NON-NLS-1$ + } + return result.toString(); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/Parser.java b/src/java/org/eclipse/jdt/internal/compiler/parser/Parser.java new file mode 100644 index 0000000..81fd8d4 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/parser/Parser.java @@ -0,0 +1,6244 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Tom Tromey - patch for readTable(String) as described in http://bugs.eclipse.org/bugs/show_bug.cgi?id=32196 + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.parser; + +import java.io.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.core.compiler.InvalidInputException; +import org.eclipse.jdt.internal.compiler.CompilationResult; +import org.eclipse.jdt.internal.compiler.ast.*; +import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; +import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; +import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; +import org.eclipse.jdt.internal.compiler.lookup.BindingIds; +import org.eclipse.jdt.internal.compiler.lookup.CompilerModifiers; +import org.eclipse.jdt.internal.compiler.lookup.TypeIds; +import org.eclipse.jdt.internal.compiler.parser.diagnose.DiagnoseParser; +import org.eclipse.jdt.internal.compiler.problem.AbortCompilation; +import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; +import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; +import org.eclipse.jdt.internal.compiler.util.Util; + +public class Parser implements BindingIds, ParserBasicInformation, TerminalTokens, CompilerModifiers, OperatorIds, TypeIds { + protected ProblemReporter problemReporter; + protected CompilerOptions options; + public int firstToken ; // handle for multiple parsing goals + public int lastAct ; //handle for multiple parsing goals + public ReferenceContext referenceContext; + public int currentToken; + private int synchronizedBlockSourceStart; + + //error recovery management + protected int lastCheckPoint; + protected RecoveredElement currentElement; + public static boolean VERBOSE_RECOVERY = false; + protected boolean restartRecovery; + protected int listLength; // for recovering some incomplete list (interfaces, throws or parameters) + protected boolean hasError; + protected boolean hasReportedError; + public boolean reportSyntaxErrorIsRequired = true; + public boolean reportOnlyOneSyntaxError = false; + protected int recoveredStaticInitializerStart; + protected int lastIgnoredToken, nextIgnoredToken; + protected int lastErrorEndPosition; + protected boolean ignoreNextOpeningBrace; + + //internal data for the automat + protected final static int StackIncrement = 255; + protected int stateStackTop; + protected int[] stack = new int[StackIncrement]; + //scanner token + public Scanner scanner; + //ast stack + final static int AstStackIncrement = 100; + protected int astPtr; + protected ASTNode[] astStack = new ASTNode[AstStackIncrement]; + protected int astLengthPtr; + protected int[] astLengthStack; + public CompilationUnitDeclaration compilationUnit; /*the result from parse()*/ + ASTNode [] noAstNodes = new ASTNode[AstStackIncrement]; + //expression stack + final static int ExpressionStackIncrement = 100; + protected int expressionPtr; + protected Expression[] expressionStack = new Expression[ExpressionStackIncrement]; + protected int expressionLengthPtr; + protected int[] expressionLengthStack; + Expression [] noExpressions = new Expression[ExpressionStackIncrement]; + //identifiers stacks + protected int identifierPtr; + protected char[][] identifierStack; + protected int identifierLengthPtr; + protected int[] identifierLengthStack; + protected long[] identifierPositionStack; + //positions , dimensions , .... (int stacks) + protected int intPtr; + protected int[] intStack; + protected int endPosition; //accurate only when used ! (the start position is pushed into intStack while the end the current one) + protected int endStatementPosition; + protected int lParenPos,rParenPos; //accurate only when used ! + protected int rBraceStart, rBraceEnd, rBraceSuccessorStart; //accurate only when used ! + //modifiers dimensions nestedType etc....... + protected boolean optimizeStringLiterals =true; + protected int modifiers; + protected int modifiersSourceStart; + protected int nestedType, dimensions; + protected int[] nestedMethod; //the ptr is nestedType + protected int[] realBlockStack; + protected int realBlockPtr; + protected boolean diet = false; //tells the scanner to jump over some parts of the code/expressions like method bodies + protected int dietInt = 0; // if > 0 force the none-diet-parsing mode (even if diet if requested) [field parsing with anonymous inner classes...] + protected int[] variablesCounter; + + // javadoc + public JavadocParser javadocParser; + public Javadoc javadoc; + + public static byte rhs[] = null; + public static char asb[] = null; + public static char asr[] = null; + public static char nasb[] = null; + public static char nasr[] = null; + + public static char terminal_index[] = null; + public static char non_terminal_index[] = null; + + public static char term_action[] = null; + public static byte term_check[] = null; + + private static final String UNEXPECTED_EOF = "Unexpected End Of File" ; //$NON-NLS-1$ + private static final String INVALID_CHARACTER = "Invalid Character" ; //$NON-NLS-1$ + private static final String EOF_TOKEN = "$eof" ; //$NON-NLS-1$ + private static final String ERROR_TOKEN = "$error" ; //$NON-NLS-1$ + + public static String name[] = null; + public static String readableName[] = null; + + public static short check_table[] = null; + public static char lhs[] = null; + public static char base_action[] = lhs; + + public static char scope_prefix[] = null; + public static char scope_suffix[] = null; + public static char scope_lhs[] = null; + + public static byte scope_la[] = null; + + public static char scope_state_set[] = null; + public static char scope_rhs[] = null; + public static char scope_state[] = null; + public static char in_symb[] = null; + + private final static String FILEPREFIX = "parser"; //$NON-NLS-1$ + private final static String READABLE_NAMES_FILE = "readableNames"; //$NON-NLS-1$ + private final static String READABLE_NAMES = + "org.eclipse.jdt.internal.compiler.parser." + READABLE_NAMES_FILE; //$NON-NLS-1$ + + static { + try{ + initTables(); + } catch(java.io.IOException ex){ + throw new ExceptionInInitializerError(ex.getMessage()); + } + } + + public static final int RoundBracket = 0; + public static final int SquareBracket = 1; + public static final int CurlyBracket = 2; + public static final int BracketKinds = 3; + +public Parser(ProblemReporter problemReporter, boolean optimizeStringLiterals) { + + this.problemReporter = problemReporter; + this.options = problemReporter.options; + this.optimizeStringLiterals = optimizeStringLiterals; + this.initializeScanner(); + this.astLengthStack = new int[50]; + this.expressionLengthStack = new int[30]; + this.intStack = new int[50]; + this.identifierStack = new char[30][]; + this.identifierLengthStack = new int[30]; + this.nestedMethod = new int[30]; + this.realBlockStack = new int[30]; + this.identifierPositionStack = new long[30]; + this.variablesCounter = new int[30]; + + // javadoc support + this.javadocParser = new JavadocParser(this); +} +/** + * + * INTERNAL USE-ONLY + */ +protected void adjustInterfaceModifiers() { + this.intStack[this.intPtr - 1] |= AccInterface; +} +public final void arrayInitializer(int length) { + //length is the size of the array Initializer + //expressionPtr points on the last elt of the arrayInitializer, + // in other words, it has not been decremented yet. + + ArrayInitializer ai = new ArrayInitializer(); + if (length != 0) { + this.expressionPtr -= length; + System.arraycopy(this.expressionStack, this.expressionPtr + 1, ai.expressions = new Expression[length], 0, length); + } + pushOnExpressionStack(ai); + //positionning + ai.sourceEnd = this.endStatementPosition; + int searchPosition = length == 0 ? this.endPosition + 1 : ai.expressions[0].sourceStart; + try { + //does not work with comments(that contain '{') nor '{' describes as a unicode.... + while (this.scanner.source[--searchPosition] != '{'){/*empty*/} + } catch (IndexOutOfBoundsException ex) { + //should never occur (except for strange cases like whose describe above) + searchPosition = (length == 0 ? this.endPosition : ai.expressions[0].sourceStart) - 1; + } + ai.sourceStart = searchPosition; +} +public static int asi(int state) { + + return asb[original_state(state)]; +} +protected void blockReal() { + // See consumeLocalVariableDeclarationStatement in case of change: duplicated code + // increment the amount of declared variables for this block + this.realBlockStack[this.realBlockPtr]++; +} +private final static void buildFileOfByteFor(String filename, String tag, String[] tokens) throws java.io.IOException { + + //transform the String tokens into chars before dumping then into file + + int i = 0; + //read upto the tag + while (!tokens[i++].equals(tag)){/*empty*/} + //read upto the } + + byte[] bytes = new byte[tokens.length]; //can't be bigger + int ic = 0; + String token; + while (!(token = tokens[i++]).equals("}")) { //$NON-NLS-1$ + int c = Integer.parseInt(token); + bytes[ic++] = (byte) c; + } + + //resize + System.arraycopy(bytes, 0, bytes = new byte[ic], 0, ic); + + buildFileForTable(filename, bytes); +} +private final static char[] buildFileOfIntFor(String filename, String tag, String[] tokens) throws java.io.IOException { + + //transform the String tokens into chars before dumping then into file + + int i = 0; + //read upto the tag + while (!tokens[i++].equals(tag)){/*empty*/} + //read upto the } + + char[] chars = new char[tokens.length]; //can't be bigger + int ic = 0; + String token; + while (!(token = tokens[i++]).equals("}")) { //$NON-NLS-1$ + int c = Integer.parseInt(token); + chars[ic++] = (char) c; + } + + //resize + System.arraycopy(chars, 0, chars = new char[ic], 0, ic); + + buildFileForTable(filename, chars); + return chars; +} +private final static void buildFileOfShortFor(String filename, String tag, String[] tokens) throws java.io.IOException { + + //transform the String tokens into chars before dumping then into file + + int i = 0; + //read upto the tag + while (!tokens[i++].equals(tag)){/*empty*/} + //read upto the } + + char[] chars = new char[tokens.length]; //can't be bigger + int ic = 0; + String token; + while (!(token = tokens[i++]).equals("}")) { //$NON-NLS-1$ + int c = Integer.parseInt(token); + chars[ic++] = (char) (c + 32768); + } + + //resize + System.arraycopy(chars, 0, chars = new char[ic], 0, ic); + + buildFileForTable(filename, chars); +} +private final static String[] buildFileForName(String filename, String contents) throws java.io.IOException { + String[] result = new String[contents.length()]; + result[0] = null; + int resultCount = 1; + + StringBuffer buffer = new StringBuffer(); + + int start = contents.indexOf("name[]"); //$NON-NLS-1$ + start = contents.indexOf('\"', start); + int end = contents.indexOf("};", start); //$NON-NLS-1$ + + contents = contents.substring(start, end); + + boolean addLineSeparator = false; + int tokenStart = -1; + StringBuffer currentToken = new StringBuffer(); + for (int i = 0; i < contents.length(); i++) { + char c = contents.charAt(i); + if(c == '\"') { + if(tokenStart == -1) { + tokenStart = i + 1; + } else { + if(addLineSeparator) { + buffer.append('\n'); + result[resultCount++] = currentToken.toString(); + currentToken = new StringBuffer(); + } + String token = contents.substring(tokenStart, i); + if(token.equals(ERROR_TOKEN)){ + token = INVALID_CHARACTER; + } else if(token.equals(EOF_TOKEN)) { + token = UNEXPECTED_EOF; + } + buffer.append(token); + currentToken.append(token); + addLineSeparator = true; + tokenStart = -1; + } + } + if(tokenStart == -1 && c == '+'){ + addLineSeparator = false; + } + } + if(currentToken.length() > 0) { + result[resultCount++] = currentToken.toString(); + } + + buildFileForTable(filename, buffer.toString().toCharArray()); + + System.arraycopy(result, 0, result = new String[resultCount], 0, resultCount); + return result; +} +private static void buildFileForReadableName( + String file, + char[] newLhs, + char[] newNonTerminalIndex, + String[] newName, + String[] tokens) throws java.io.IOException { + + ArrayList entries = new ArrayList(); + + boolean[] alreadyAdded = new boolean[newName.length]; + + for (int i = 0; i < tokens.length; i = i + 2) { + int index = newNonTerminalIndex[newLhs[Integer.parseInt(tokens[i])]]; + StringBuffer buffer = new StringBuffer(); + if(!alreadyAdded[index]) { + alreadyAdded[index] = true; + buffer.append(newName[index]); + buffer.append('='); + buffer.append(tokens[i+1].trim()); + buffer.append('\n'); + entries.add(String.valueOf(buffer)); + } + } + int i = 1; + while(!INVALID_CHARACTER.equals(newName[i])) i++; + i++; + for (; i < alreadyAdded.length; i++) { + if(!alreadyAdded[i]) { + System.out.println(newName[i] + " has no readable name"); //$NON-NLS-1$ + } + } + Collections.sort(entries); + buildFile(file, entries); +} +private final static void buildFile(String filename, List listToDump) throws java.io.IOException { + BufferedWriter writer = new BufferedWriter(new FileWriter(filename)); + for (Iterator iterator = listToDump.iterator(); iterator.hasNext(); ) { + writer.write(String.valueOf(iterator.next())); + } + writer.flush(); + writer.close(); + System.out.println(filename + " creation complete"); //$NON-NLS-1$ +} +private final static void buildFileForTable(String filename, char[] chars) throws java.io.IOException { + + byte[] bytes = new byte[chars.length * 2]; + for (int i = 0; i < chars.length; i++) { + bytes[2 * i] = (byte) (chars[i] >>> 8); + bytes[2 * i + 1] = (byte) (chars[i] & 0xFF); + } + + java.io.FileOutputStream stream = new java.io.FileOutputStream(filename); + stream.write(bytes); + stream.close(); + System.out.println(filename + " creation complete"); //$NON-NLS-1$ +} +private final static void buildFileForTable(String filename, byte[] bytes) throws java.io.IOException { + java.io.FileOutputStream stream = new java.io.FileOutputStream(filename); + stream.write(bytes); + stream.close(); + System.out.println(filename + " creation complete"); //$NON-NLS-1$ +} +public final static void buildFilesFromLPG(String dataFilename, String dataFilename2) throws java.io.IOException { + + //RUN THIS METHOD TO GENERATE PARSER*.RSC FILES + + //build from the lpg javadcl.java files that represents the parser tables + //lhs check_table asb asr symbol_index + + //[org.eclipse.jdt.internal.compiler.parser.Parser.buildFilesFromLPG("d:/leapfrog/grammar/javadcl.java")] + + char[] contents = new char[] {}; + try { + contents = Util.getFileCharContent(new File(dataFilename), null); + } catch (IOException ex) { + System.out.println(Util.bind("parser.incorrectPath")); //$NON-NLS-1$ + return; + } + java.util.StringTokenizer st = + new java.util.StringTokenizer(new String(contents), " \t\n\r[]={,;"); //$NON-NLS-1$ + String[] tokens = new String[st.countTokens()]; + int i = 0; + while (st.hasMoreTokens()) { + tokens[i++] = st.nextToken(); + } + final String prefix = FILEPREFIX; + i = 0; + + char[] newLhs = buildFileOfIntFor(prefix + (++i) + ".rsc", "lhs", tokens); //$NON-NLS-1$ //$NON-NLS-2$ + buildFileOfShortFor(prefix + (++i) + ".rsc", "check_table", tokens); //$NON-NLS-2$ //$NON-NLS-1$ + buildFileOfIntFor(prefix + (++i) + ".rsc", "asb", tokens); //$NON-NLS-2$ //$NON-NLS-1$ + buildFileOfIntFor(prefix + (++i) + ".rsc", "asr", tokens); //$NON-NLS-2$ //$NON-NLS-1$ + buildFileOfIntFor(prefix + (++i) + ".rsc", "nasb", tokens); //$NON-NLS-2$ //$NON-NLS-1$ + buildFileOfIntFor(prefix + (++i) + ".rsc", "nasr", tokens); //$NON-NLS-2$ //$NON-NLS-1$ + buildFileOfIntFor(prefix + (++i) + ".rsc", "terminal_index", tokens); //$NON-NLS-2$ //$NON-NLS-1$ + char[] newNonTerminalIndex = buildFileOfIntFor(prefix + (++i) + ".rsc", "non_terminal_index", tokens); //$NON-NLS-1$ //$NON-NLS-2$ + buildFileOfIntFor(prefix + (++i) + ".rsc", "term_action", tokens); //$NON-NLS-2$ //$NON-NLS-1$ + + buildFileOfIntFor(prefix + (++i) + ".rsc", "scope_prefix", tokens); //$NON-NLS-2$ //$NON-NLS-1$ + buildFileOfIntFor(prefix + (++i) + ".rsc", "scope_suffix", tokens); //$NON-NLS-2$ //$NON-NLS-1$ + buildFileOfIntFor(prefix + (++i) + ".rsc", "scope_lhs", tokens); //$NON-NLS-2$ //$NON-NLS-1$ + buildFileOfIntFor(prefix + (++i) + ".rsc", "scope_state_set", tokens); //$NON-NLS-2$ //$NON-NLS-1$ + buildFileOfIntFor(prefix + (++i) + ".rsc", "scope_rhs", tokens); //$NON-NLS-2$ //$NON-NLS-1$ + buildFileOfIntFor(prefix + (++i) + ".rsc", "scope_state", tokens); //$NON-NLS-2$ //$NON-NLS-1$ + buildFileOfIntFor(prefix + (++i) + ".rsc", "in_symb", tokens); //$NON-NLS-2$ //$NON-NLS-1$ + + buildFileOfByteFor(prefix + (++i) + ".rsc", "rhs", tokens); //$NON-NLS-2$ //$NON-NLS-1$ + buildFileOfByteFor(prefix + (++i) + ".rsc", "term_check", tokens); //$NON-NLS-2$ //$NON-NLS-1$ + buildFileOfByteFor(prefix + (++i) + ".rsc", "scope_la", tokens); //$NON-NLS-2$ //$NON-NLS-1$ + + String[] newName = buildFileForName(prefix + (++i) + ".rsc", new String(contents)); //$NON-NLS-1$ + + contents = new char[] {}; + try { + contents = Util.getFileCharContent(new File(dataFilename2), null); + } catch (IOException ex) { + System.out.println(Util.bind("parser.incorrectPath")); //$NON-NLS-1$ + return; + } + st = new java.util.StringTokenizer(new String(contents), "\t\n\r="); //$NON-NLS-1$ + tokens = new String[st.countTokens()]; + i = 0; + while (st.hasMoreTokens()) { + tokens[i++] = st.nextToken(); + } + buildFileForReadableName(READABLE_NAMES_FILE+".properties", newLhs, newNonTerminalIndex, newName, tokens);//$NON-NLS-1$ + + System.out.println(Util.bind("parser.moveFiles")); //$NON-NLS-1$ +} +/* + * Build initial recovery state. + * Recovery state is inferred from the current state of the parser (reduced node stack). + */ +public RecoveredElement buildInitialRecoveryState(){ + + /* initialize recovery by retrieving available reduced nodes + * also rebuild bracket balance + */ + this.lastCheckPoint = 0; + + RecoveredElement element = null; + if (this.referenceContext instanceof CompilationUnitDeclaration){ + element = new RecoveredUnit(this.compilationUnit, 0, this); + + /* ignore current stack state, since restarting from the beginnning + since could not trust simple brace count */ + if (true){ // experimenting restart recovery from scratch + this.compilationUnit.currentPackage = null; + this.compilationUnit.imports = null; + this.compilationUnit.types = null; + this.currentToken = 0; + this.listLength = 0; + this.endPosition = 0; + this.endStatementPosition = 0; + return element; + } + if (this.compilationUnit.currentPackage != null){ + this.lastCheckPoint = this.compilationUnit.currentPackage.declarationSourceEnd+1; + } + if (this.compilationUnit.imports != null){ + this.lastCheckPoint = this.compilationUnit.imports[this.compilationUnit.imports.length -1].declarationSourceEnd+1; + } + } else { + if (this.referenceContext instanceof AbstractMethodDeclaration){ + element = new RecoveredMethod((AbstractMethodDeclaration) this.referenceContext, null, 0, this); + this.lastCheckPoint = ((AbstractMethodDeclaration) this.referenceContext).bodyStart; + } else { + /* Initializer bodies are parsed in the context of the type declaration, we must thus search it inside */ + if (this.referenceContext instanceof TypeDeclaration){ + TypeDeclaration type = (TypeDeclaration) this.referenceContext; + for (int i = 0; i < type.fields.length; i++){ + FieldDeclaration field = type.fields[i]; + if (field != null + && !field.isField() + && field.declarationSourceStart <= this.scanner.initialPosition + && this.scanner.initialPosition <= field.declarationSourceEnd + && this.scanner.eofPosition <= field.declarationSourceEnd+1){ + element = new RecoveredInitializer(field, null, 1, this); + this.lastCheckPoint = field.declarationSourceStart; + break; + } + } + } + } + } + + if (element == null) return element; + + for(int i = 0; i <= this.astPtr; i++){ + ASTNode node = this.astStack[i]; + if (node instanceof AbstractMethodDeclaration){ + AbstractMethodDeclaration method = (AbstractMethodDeclaration) node; + if (method.declarationSourceEnd == 0){ + element = element.add(method, 0); + this.lastCheckPoint = method.bodyStart; + } else { + element = element.add(method, 0); + this.lastCheckPoint = method.declarationSourceEnd + 1; + } + continue; + } + if (node instanceof Initializer){ + Initializer initializer = (Initializer) node; + if (initializer.declarationSourceEnd == 0){ + element = element.add(initializer, 1); + this.lastCheckPoint = initializer.sourceStart; + } else { + element = element.add(initializer, 0); + this.lastCheckPoint = initializer.declarationSourceEnd + 1; + } + continue; + } + if (node instanceof FieldDeclaration){ + FieldDeclaration field = (FieldDeclaration) node; + if (field.declarationSourceEnd == 0){ + element = element.add(field, 0); + if (field.initialization == null){ + this.lastCheckPoint = field.sourceEnd + 1; + } else { + this.lastCheckPoint = field.initialization.sourceEnd + 1; + } + } else { + element = element.add(field, 0); + this.lastCheckPoint = field.declarationSourceEnd + 1; + } + continue; + } + if (node instanceof TypeDeclaration){ + TypeDeclaration type = (TypeDeclaration) node; + if (type.declarationSourceEnd == 0){ + element = element.add(type, 0); + this.lastCheckPoint = type.bodyStart; + } else { + element = element.add(type, 0); + this.lastCheckPoint = type.declarationSourceEnd + 1; + } + continue; + } + if (node instanceof ImportReference){ + ImportReference importRef = (ImportReference) node; + element = element.add(importRef, 0); + this.lastCheckPoint = importRef.declarationSourceEnd + 1; + } + } + return element; +} +public final static short base_check(int i) { + return check_table[i - (NUM_RULES + 1)]; +} +public final void checkAndSetModifiers(int flag){ + /*modify the current modifiers buffer. + When the startPosition of the modifiers is 0 + it means that the modifier being parsed is the first + of a list of several modifiers. The startPosition + is zeroed when a copy of modifiers-buffer is push + onto the astStack. */ + + if ((this.modifiers & flag) != 0){ // duplicate modifier + this.modifiers |= AccAlternateModifierProblem; + } + this.modifiers |= flag; + + if (this.modifiersSourceStart < 0) this.modifiersSourceStart = this.scanner.startPosition; +} +public void checkComment() { + + if (this.currentElement != null && this.scanner.commentPtr >= 0) { + flushCommentsDefinedPriorTo(this.endStatementPosition); // discard obsolete comments during recovery + } + + int lastComment = this.scanner.commentPtr; + + if (this.modifiersSourceStart >= 0) { + // eliminate comments located after modifierSourceStart if positionned + while (lastComment >= 0 && this.scanner.commentStarts[lastComment] > this.modifiersSourceStart) lastComment--; + } + if (lastComment >= 0) { + // consider all remaining leading comments to be part of current declaration + this.modifiersSourceStart = this.scanner.commentStarts[0]; + + // check deprecation in last comment if javadoc (can be followed by non-javadoc comments which are simply ignored) + while (lastComment >= 0 && this.scanner.commentStops[lastComment] < 0) lastComment--; // non javadoc comment have negative end positions + if (lastComment >= 0 && this.javadocParser != null) { + if (this.javadocParser.checkDeprecation( + this.scanner.commentStarts[lastComment], + this.scanner.commentStops[lastComment] - 1)) { //stop is one over, + checkAndSetModifiers(AccDeprecated); + } + this.javadoc = this.javadocParser.docComment; // null if check javadoc is not activated + } + } +} +protected void checkNonExternalizedStringLiteral() { + if (this.scanner.wasNonExternalizedStringLiteral) { + StringLiteral[] literals = this.scanner.nonNLSStrings; + // could not reproduce, but this is the only NPE + // added preventive null check see PR 9035 + if (literals != null) { + for (int i = 0, max = literals.length; i < max; i++) { + problemReporter().nonExternalizedStringLiteral(literals[i]); + } + } + this.scanner.wasNonExternalizedStringLiteral = false; + } +} +protected void checkNonNLSAfterBodyEnd(int declarationEnd){ + if(this.scanner.currentPosition - 1 <= declarationEnd) { + this.scanner.eofPosition = declarationEnd < Integer.MAX_VALUE ? declarationEnd + 1 : declarationEnd; + try { + while(this.scanner.getNextToken() != TokenNameEOF){/*empty*/} + checkNonExternalizedStringLiteral(); + } catch (InvalidInputException e) { + // Nothing to do + } + } +} +protected char getNextCharacter(char[] comment, int[] index) { + char nextCharacter = comment[index[0]++]; + switch(nextCharacter) { + case '\\' : + int c1, c2, c3, c4; + index[0]++; + while (comment[index[0]] == 'u') index[0]++; + if (!(((c1 = Character.getNumericValue(comment[index[0]++])) > 15 + || c1 < 0) + || ((c2 = Character.getNumericValue(comment[index[0]++])) > 15 || c2 < 0) + || ((c3 = Character.getNumericValue(comment[index[0]++])) > 15 || c3 < 0) + || ((c4 = Character.getNumericValue(comment[index[0]++])) > 15 || c4 < 0))) { + nextCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + } + break; + } + return nextCharacter; +} +protected void classInstanceCreation(boolean alwaysQualified) { + // ClassInstanceCreationExpression ::= 'new' ClassType '(' ArgumentListopt ')' ClassBodyopt + + // ClassBodyopt produces a null item on the astStak if it produces NO class body + // An empty class body produces a 0 on the length stack..... + + AllocationExpression alloc; + int length; + if (((length = this.astLengthStack[this.astLengthPtr--]) == 1) + && (this.astStack[this.astPtr] == null)) { + //NO ClassBody + this.astPtr--; + if (alwaysQualified) { + alloc = new QualifiedAllocationExpression(); + } else { + alloc = new AllocationExpression(); + } + alloc.sourceEnd = this.endPosition; //the position has been stored explicitly + + if ((length = this.expressionLengthStack[this.expressionLengthPtr--]) != 0) { + this.expressionPtr -= length; + System.arraycopy( + this.expressionStack, + this.expressionPtr + 1, + alloc.arguments = new Expression[length], + 0, + length); + } + alloc.type = getTypeReference(0); + //the default constructor with the correct number of argument + //will be created and added by the TC (see createsInternalConstructorWithBinding) + alloc.sourceStart = this.intStack[this.intPtr--]; + pushOnExpressionStack(alloc); + } else { + dispatchDeclarationInto(length); + TypeDeclaration anonymousTypeDeclaration = (TypeDeclaration)this.astStack[this.astPtr]; + anonymousTypeDeclaration.declarationSourceEnd = this.endStatementPosition; + anonymousTypeDeclaration.bodyEnd = this.endStatementPosition; + if (anonymousTypeDeclaration.allocation != null) { + anonymousTypeDeclaration.allocation.sourceEnd = this.endStatementPosition; + } + if (length == 0 && !containsComment(anonymousTypeDeclaration.bodyStart, anonymousTypeDeclaration.bodyEnd)) { + anonymousTypeDeclaration.bits |= ASTNode.UndocumentedEmptyBlockMASK; + } + this.astPtr--; + this.astLengthPtr--; + + // mark initializers with local type mark if needed + markInitializersWithLocalType(anonymousTypeDeclaration); + } +} +protected final void concatExpressionLists() { + this.expressionLengthStack[--this.expressionLengthPtr]++; +} +private final void concatNodeLists() { + /* + * This is a case where you have two sublists into the astStack that you want + * to merge in one list. There is no action required on the astStack. The only + * thing you need to do is merge the two lengths specified on the astStackLength. + * The top two length are for example: + * ... p n + * and you want to result in a list like: + * ... n+p + * This means that the p could be equals to 0 in case there is no astNode pushed + * on the astStack. + * Look at the InterfaceMemberDeclarations for an example. + */ + + this.astLengthStack[this.astLengthPtr - 1] += this.astLengthStack[this.astLengthPtr--]; +} +protected void consumeAllocationHeader() { + // ClassInstanceCreationExpression ::= 'new' ClassType '(' ArgumentListopt ')' ClassBodyopt + + // ClassBodyopt produces a null item on the astStak if it produces NO class body + // An empty class body produces a 0 on the length stack..... + + if (this.currentElement == null){ + return; // should never occur, this consumeRule is only used in recovery mode + } + if (this.currentToken == TokenNameLBRACE){ + // beginning of an anonymous type + TypeDeclaration anonymousType = new TypeDeclaration(this.compilationUnit.compilationResult); + anonymousType.name = TypeDeclaration.ANONYMOUS_EMPTY_NAME; + anonymousType.bits |= ASTNode.AnonymousAndLocalMask; + anonymousType.sourceStart = this.intStack[this.intPtr--]; + anonymousType.sourceEnd = this.rParenPos; // closing parenthesis + QualifiedAllocationExpression alloc = new QualifiedAllocationExpression(anonymousType); + alloc.type = getTypeReference(0); + alloc.sourceStart = anonymousType.sourceStart; + alloc.sourceEnd = anonymousType.sourceEnd ; + anonymousType.allocation = alloc; + this.lastCheckPoint = anonymousType.bodyStart = this.scanner.currentPosition; + this.currentElement = this.currentElement.add(anonymousType, 0); + this.lastIgnoredToken = -1; + this.currentToken = 0; // opening brace already taken into account + return; + } + this.lastCheckPoint = this.scanner.startPosition; // force to restart at this exact position + this.restartRecovery = true; // request to restart from here on +} +protected void consumeArgumentList() { + // ArgumentList ::= ArgumentList ',' Expression + concatExpressionLists(); +} +protected void consumeArrayAccess(boolean unspecifiedReference) { + // ArrayAccess ::= Name '[' Expression ']' ==> true + // ArrayAccess ::= PrimaryNoNewArray '[' Expression ']' ==> false + + + //optimize push/pop + Expression exp; + if (unspecifiedReference) { + exp = + this.expressionStack[this.expressionPtr] = + new ArrayReference( + getUnspecifiedReferenceOptimized(), + this.expressionStack[this.expressionPtr]); + } else { + this.expressionPtr--; + this.expressionLengthPtr--; + exp = + this.expressionStack[this.expressionPtr] = + new ArrayReference( + this.expressionStack[this.expressionPtr], + this.expressionStack[this.expressionPtr + 1]); + } + exp.sourceEnd = this.endPosition; +} +protected void consumeArrayCreationExpressionWithoutInitializer() { + // ArrayCreationWithoutArrayInitializer ::= 'new' ClassOrInterfaceType DimWithOrWithOutExprs + // ArrayCreationWithoutArrayInitializer ::= 'new' PrimitiveType DimWithOrWithOutExprs + + int length; + ArrayAllocationExpression aae = new ArrayAllocationExpression(); + aae.type = getTypeReference(0); + length = (this.expressionLengthStack[this.expressionLengthPtr--]); + this.expressionPtr -= length ; + System.arraycopy( + this.expressionStack, + this.expressionPtr+1, + aae.dimensions = new Expression[length], + 0, + length); + aae.sourceStart = this.intStack[this.intPtr--]; + if (aae.initializer == null) { + aae.sourceEnd = this.endPosition; + } else { + aae.sourceEnd = aae.initializer.sourceEnd ; + } + pushOnExpressionStack(aae); +} + +protected void consumeArrayCreationHeader() { + // nothing to do +} +protected void consumeArrayCreationExpressionWithInitializer() { + // ArrayCreationWithArrayInitializer ::= 'new' PrimitiveType DimWithOrWithOutExprs ArrayInitializer + // ArrayCreationWithArrayInitializer ::= 'new' ClassOrInterfaceType DimWithOrWithOutExprs ArrayInitializer + + int length; + ArrayAllocationExpression aae = new ArrayAllocationExpression(); + this.expressionLengthPtr -- ; + aae.initializer = (ArrayInitializer) this.expressionStack[this.expressionPtr--]; + + aae.type = getTypeReference(0); + length = (this.expressionLengthStack[this.expressionLengthPtr--]); + this.expressionPtr -= length ; + System.arraycopy( + this.expressionStack, + this.expressionPtr+1, + aae.dimensions = new Expression[length], + 0, + length); + aae.sourceStart = this.intStack[this.intPtr--]; + if (aae.initializer == null) { + aae.sourceEnd = this.endPosition; + } else { + aae.sourceEnd = aae.initializer.sourceEnd ; + } + pushOnExpressionStack(aae); +} +protected void consumeArrayInitializer() { + // ArrayInitializer ::= '{' VariableInitializers '}' + // ArrayInitializer ::= '{' VariableInitializers , '}' + + arrayInitializer(this.expressionLengthStack[this.expressionLengthPtr--]); +} + +protected void consumeAssertStatement() { + // AssertStatement ::= 'assert' Expression ':' Expression ';' + this.expressionLengthPtr-=2; + pushOnAstStack(new AssertStatement(this.expressionStack[this.expressionPtr--], this.expressionStack[this.expressionPtr--], this.intStack[this.intPtr--])); +} + +protected void consumeAssignment() { + // Assignment ::= LeftHandSide AssignmentOperator AssignmentExpression + //optimize the push/pop + + int op = this.intStack[this.intPtr--] ; //<--the encoded operator + + this.expressionPtr -- ; this.expressionLengthPtr -- ; + this.expressionStack[this.expressionPtr] = + (op != EQUAL ) ? + new CompoundAssignment( + this.expressionStack[this.expressionPtr] , + this.expressionStack[this.expressionPtr+1], + op, + this.scanner.startPosition - 1) : + new Assignment( + this.expressionStack[this.expressionPtr] , + this.expressionStack[this.expressionPtr+1], + this.scanner.startPosition - 1); +} +protected void consumeAssignmentOperator(int pos) { + // AssignmentOperator ::= '=' + // AssignmentOperator ::= '*=' + // AssignmentOperator ::= '/=' + // AssignmentOperator ::= '%=' + // AssignmentOperator ::= '+=' + // AssignmentOperator ::= '-=' + // AssignmentOperator ::= '<<=' + // AssignmentOperator ::= '>>=' + // AssignmentOperator ::= '>>>=' + // AssignmentOperator ::= '&=' + // AssignmentOperator ::= '^=' + // AssignmentOperator ::= '|=' + + pushOnIntStack(pos); +} +protected void consumeBinaryExpression(int op) { + // MultiplicativeExpression ::= MultiplicativeExpression '*' UnaryExpression + // MultiplicativeExpression ::= MultiplicativeExpression '/' UnaryExpression + // MultiplicativeExpression ::= MultiplicativeExpression '%' UnaryExpression + // AdditiveExpression ::= AdditiveExpression '+' MultiplicativeExpression + // AdditiveExpression ::= AdditiveExpression '-' MultiplicativeExpression + // ShiftExpression ::= ShiftExpression '<<' AdditiveExpression + // ShiftExpression ::= ShiftExpression '>>' AdditiveExpression + // ShiftExpression ::= ShiftExpression '>>>' AdditiveExpression + // RelationalExpression ::= RelationalExpression '<' ShiftExpression + // RelationalExpression ::= RelationalExpression '>' ShiftExpression + // RelationalExpression ::= RelationalExpression '<=' ShiftExpression + // RelationalExpression ::= RelationalExpression '>=' ShiftExpression + // AndExpression ::= AndExpression '&' EqualityExpression + // ExclusiveOrExpression ::= ExclusiveOrExpression '^' AndExpression + // InclusiveOrExpression ::= InclusiveOrExpression '|' ExclusiveOrExpression + // ConditionalAndExpression ::= ConditionalAndExpression '&&' InclusiveOrExpression + // ConditionalOrExpression ::= ConditionalOrExpression '||' ConditionalAndExpression + + //optimize the push/pop + + this.expressionPtr--; + this.expressionLengthPtr--; + Expression expr1 = this.expressionStack[this.expressionPtr]; + Expression expr2 = this.expressionStack[this.expressionPtr + 1]; + switch(op) { + case OR_OR : + this.expressionStack[this.expressionPtr] = + new OR_OR_Expression( + expr1, + expr2, + op); + break; + case AND_AND : + this.expressionStack[this.expressionPtr] = + new AND_AND_Expression( + expr1, + expr2, + op); + break; + case PLUS : + // look for "string1" + "string2" + if (this.optimizeStringLiterals) { + if (expr1 instanceof StringLiteral) { + if (expr2 instanceof CharLiteral) { // string+char + this.expressionStack[this.expressionPtr] = + ((StringLiteral) expr1).extendWith((CharLiteral) expr2); + } else if (expr2 instanceof StringLiteral) { //string+string + this.expressionStack[this.expressionPtr] = + ((StringLiteral) expr1).extendWith((StringLiteral) expr2); + } else { + this.expressionStack[this.expressionPtr] = new BinaryExpression(expr1, expr2, PLUS); + } + } else { + this.expressionStack[this.expressionPtr] = new BinaryExpression(expr1, expr2, PLUS); + } + } else if (expr1 instanceof StringLiteral) { + if (expr2 instanceof StringLiteral) { + // string + string + this.expressionStack[this.expressionPtr] = + ((StringLiteral) expr1).extendsWith((StringLiteral) expr2); + } else { + this.expressionStack[this.expressionPtr] = + new BinaryExpression( + expr1, + expr2, + op); + } + } else { + this.expressionStack[this.expressionPtr] = + new BinaryExpression( + expr1, + expr2, + op); + } + break; + default : + this.expressionStack[this.expressionPtr] = + new BinaryExpression( + expr1, + expr2, + op); + } +} +protected void consumeBlock() { + // Block ::= OpenBlock '{' BlockStatementsopt '}' + // simpler action for empty blocks + + int statementsLength = this.astLengthStack[this.astLengthPtr--]; + Block block; + if (statementsLength == 0) { // empty block + block = new Block(0); + block.sourceStart = this.intStack[this.intPtr--]; + block.sourceEnd = this.endStatementPosition; + // check whether this block at least contains some comment in it + if (!containsComment(block.sourceStart, block.sourceEnd)) { + block.bits |= ASTNode.UndocumentedEmptyBlockMASK; + } + this.realBlockPtr--; // still need to pop the block variable counter + } else { + block = new Block(this.realBlockStack[this.realBlockPtr--]); + this.astPtr -= statementsLength; + System.arraycopy( + this.astStack, + this.astPtr + 1, + block.statements = new Statement[statementsLength], + 0, + statementsLength); + block.sourceStart = this.intStack[this.intPtr--]; + block.sourceEnd = this.endStatementPosition; + } + pushOnAstStack(block); +} +protected void consumeBlockStatements() { + // BlockStatements ::= BlockStatements BlockStatement + concatNodeLists(); +} +protected void consumeCaseLabel() { + // SwitchLabel ::= 'case' ConstantExpression ':' + this.expressionLengthPtr--; + Expression expression = this.expressionStack[this.expressionPtr--]; + pushOnAstStack(new CaseStatement(expression, expression.sourceEnd, this.intStack[this.intPtr--])); +} +protected void consumeCastExpression() { + // CastExpression ::= PushLPAREN PrimitiveType Dimsopt PushRPAREN InsideCastExpression UnaryExpression + // CastExpression ::= PushLPAREN Name Dims PushRPAREN InsideCastExpression UnaryExpressionNotPlusMinus + + //this.intStack : posOfLeftParen dim posOfRightParen + + //optimize the push/pop + + Expression exp, cast, castType; + int end = this.intStack[this.intPtr--]; + this.expressionStack[this.expressionPtr] = cast = new CastExpression(exp = this.expressionStack[this.expressionPtr], castType = getTypeReference(this.intStack[this.intPtr--])); + castType.sourceEnd = end - 1; + castType.sourceStart = (cast.sourceStart = this.intStack[this.intPtr--]) + 1; + cast.sourceEnd = exp.sourceEnd; +} +protected void consumeCastExpressionLL1() { + //CastExpression ::= '(' Expression ')' InsideCastExpressionLL1 UnaryExpressionNotPlusMinus + // Expression is used in order to make the grammar LL1 + + //optimize push/pop + + Expression cast,exp; + this.expressionPtr--; + this.expressionStack[this.expressionPtr] = + cast = new CastExpression( + exp=this.expressionStack[this.expressionPtr+1] , + getTypeReference(this.expressionStack[this.expressionPtr])); + this.expressionLengthPtr -- ; + updateSourcePosition(cast); + cast.sourceEnd=exp.sourceEnd; +} +protected void consumeCatches() { + // Catches ::= Catches CatchClause + optimizedConcatNodeLists(); +} +protected void consumeCatchHeader() { + // CatchDeclaration ::= 'catch' '(' FormalParameter ')' '{' + + if (this.currentElement == null){ + return; // should never occur, this consumeRule is only used in recovery mode + } + // current element should be a block due to the presence of the opening brace + if (!(this.currentElement instanceof RecoveredBlock)){ + if(!(this.currentElement instanceof RecoveredMethod)) { + return; + } + RecoveredMethod rMethod = (RecoveredMethod) this.currentElement; + if(!(rMethod.methodBody == null && rMethod.bracketBalance > 0)) { + return; + } + } + + Argument arg = (Argument)this.astStack[this.astPtr--]; + // convert argument to local variable + LocalDeclaration localDeclaration = new LocalDeclaration(arg.name, arg.sourceStart, arg.sourceEnd); + localDeclaration.type = arg.type; + localDeclaration.declarationSourceStart = arg.declarationSourceStart; + localDeclaration.declarationSourceEnd = arg.declarationSourceEnd; + + this.currentElement = this.currentElement.add(localDeclaration, 0); + this.lastCheckPoint = this.scanner.startPosition; // force to restart at this exact position + this.restartRecovery = true; // request to restart from here on + this.lastIgnoredToken = -1; +} +protected void consumeClassBodyDeclaration() { + // ClassBodyDeclaration ::= Diet Block + //push an Initializer + //optimize the push/pop + this.nestedMethod[this.nestedType]--; + Block block = (Block) this.astStack[this.astPtr]; + if (this.diet) block.bits &= ~ASTNode.UndocumentedEmptyBlockMASK; // clear bit since was diet + Initializer initializer = new Initializer(block, 0); + this.intPtr--; // pop sourcestart left on the stack by consumeNestedMethod. + initializer.bodyStart = this.intStack[this.intPtr--]; + this.realBlockPtr--; // pop the block variable counter left on the stack by consumeNestedMethod + int javadocCommentStart = this.intStack[this.intPtr--]; + if (javadocCommentStart != -1) { + initializer.declarationSourceStart = javadocCommentStart; + initializer.javadoc = this.javadoc; + this.javadoc = null; + } + this.astStack[this.astPtr] = initializer; + initializer.bodyEnd = this.endPosition; + initializer.sourceEnd = this.endStatementPosition; + initializer.declarationSourceEnd = flushCommentsDefinedPriorTo(this.endStatementPosition); +} +protected void consumeClassBodyDeclarations() { + // ClassBodyDeclarations ::= ClassBodyDeclarations ClassBodyDeclaration + concatNodeLists(); +} +protected void consumeClassBodyDeclarationsopt() { + // ClassBodyDeclarationsopt ::= NestedType ClassBodyDeclarations + this.nestedType-- ; +} +protected void consumeClassBodyopt() { + // ClassBodyopt ::= $empty + pushOnAstStack(null); + this.endPosition = this.scanner.startPosition - 1; +} +protected void consumeClassDeclaration() { + // ClassDeclaration ::= ClassHeader ClassBody + + int length; + if ((length = this.astLengthStack[this.astLengthPtr--]) != 0) { + //there are length declarations + //dispatch according to the type of the declarations + dispatchDeclarationInto(length); + } + + TypeDeclaration typeDecl = (TypeDeclaration) this.astStack[this.astPtr]; + + // mark initializers with local type mark if needed + markInitializersWithLocalType(typeDecl); + + //convert constructor that do not have the type's name into methods + boolean hasConstructor = typeDecl.checkConstructors(this); + + //add the default constructor when needed (interface don't have it) + if (!hasConstructor && !typeDecl.isInterface()) { + boolean insideFieldInitializer = false; + if (this.diet) { + for (int i = this.nestedType; i > 0; i--){ + if (this.variablesCounter[i] > 0) { + insideFieldInitializer = true; + break; + } + } + } + typeDecl.createsInternalConstructor(!this.diet || insideFieldInitializer, true); + } + + //always add (will be remove at code gen time if empty) + if (this.scanner.containsAssertKeyword) { + typeDecl.bits |= ASTNode.AddAssertionMASK; + } + typeDecl.addClinit(); + typeDecl.bodyEnd = this.endStatementPosition; + if (length == 0 && !containsComment(typeDecl.bodyStart, typeDecl.bodyEnd)) { + typeDecl.bits |= ASTNode.UndocumentedEmptyBlockMASK; + } + + typeDecl.declarationSourceEnd = flushCommentsDefinedPriorTo(this.endStatementPosition); +} +protected void consumeClassHeader() { + // ClassHeader ::= ClassHeaderName ClassHeaderExtendsopt ClassHeaderImplementsopt + + TypeDeclaration typeDecl = (TypeDeclaration) this.astStack[this.astPtr]; + if (this.currentToken == TokenNameLBRACE) { + typeDecl.bodyStart = this.scanner.currentPosition; + } + if (this.currentElement != null) { + this.restartRecovery = true; // used to avoid branching back into the regular automaton + } + // flush the comments related to the class header + this.scanner.commentPtr = -1; +} +protected void consumeClassHeaderExtends() { + // ClassHeaderExtends ::= 'extends' ClassType + // There is a class declaration on the top of stack + TypeDeclaration typeDecl = (TypeDeclaration) this.astStack[this.astPtr]; + //superclass + typeDecl.superclass = getTypeReference(0); + typeDecl.bodyStart = typeDecl.superclass.sourceEnd + 1; + // recovery + if (this.currentElement != null){ + this.lastCheckPoint = typeDecl.bodyStart; + } +} +protected void consumeClassHeaderImplements() { + // ClassHeaderImplements ::= 'implements' InterfaceTypeList + int length = this.astLengthStack[this.astLengthPtr--]; + //super interfaces + this.astPtr -= length; + // There is a class declaration on the top of stack + TypeDeclaration typeDecl = (TypeDeclaration) this.astStack[this.astPtr]; + System.arraycopy( + this.astStack, + this.astPtr + 1, + typeDecl.superInterfaces = new TypeReference[length], + 0, + length); + typeDecl.bodyStart = typeDecl.superInterfaces[length-1].sourceEnd + 1; + this.listLength = 0; // reset after having read super-interfaces + // recovery + if (this.currentElement != null) { // is recovering + this.lastCheckPoint = typeDecl.bodyStart; + } +} +protected void consumeClassHeaderName() { + // ClassHeaderName ::= Modifiersopt 'class' 'Identifier' + TypeDeclaration typeDecl = new TypeDeclaration(this.compilationUnit.compilationResult); + if (this.nestedMethod[this.nestedType] == 0) { + if (this.nestedType != 0) { + typeDecl.bits |= ASTNode.IsMemberTypeMASK; + } + } else { + // Record that the block has a declaration for local types + typeDecl.bits |= ASTNode.IsLocalTypeMASK; + markEnclosingMemberWithLocalType(); + blockReal(); + } + + //highlight the name of the type + long pos = this.identifierPositionStack[this.identifierPtr]; + typeDecl.sourceEnd = (int) pos; + typeDecl.sourceStart = (int) (pos >>> 32); + typeDecl.name = this.identifierStack[this.identifierPtr--]; + this.identifierLengthPtr--; + + //compute the declaration source too + // 'class' and 'interface' push two int positions: the beginning of the class token and its end. + // we want to keep the beginning position but get rid of the end position + // it is only used for the ClassLiteralAccess positions. + typeDecl.declarationSourceStart = this.intStack[this.intPtr--]; + this.intPtr--; // remove the end position of the class token + + typeDecl.modifiersSourceStart = this.intStack[this.intPtr--]; + typeDecl.modifiers = this.intStack[this.intPtr--]; + if (typeDecl.modifiersSourceStart >= 0) { + typeDecl.declarationSourceStart = typeDecl.modifiersSourceStart; + } + typeDecl.bodyStart = typeDecl.sourceEnd + 1; + pushOnAstStack(typeDecl); + + this.listLength = 0; // will be updated when reading super-interfaces + // recovery + if (this.currentElement != null){ + this.lastCheckPoint = typeDecl.bodyStart; + this.currentElement = this.currentElement.add(typeDecl, 0); + this.lastIgnoredToken = -1; + } + // javadoc + typeDecl.javadoc = this.javadoc; + this.javadoc = null; +} +protected void consumeClassInstanceCreationExpression() { + // ClassInstanceCreationExpression ::= 'new' ClassType '(' ArgumentListopt ')' ClassBodyopt + classInstanceCreation(false); +} +protected void consumeClassInstanceCreationExpressionName() { + // ClassInstanceCreationExpressionName ::= Name '.' + pushOnExpressionStack(getUnspecifiedReferenceOptimized()); +} +protected void consumeClassInstanceCreationExpressionQualified() { + // ClassInstanceCreationExpression ::= Primary '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt + // ClassInstanceCreationExpression ::= ClassInstanceCreationExpressionName 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt + + classInstanceCreation(true); // <-- push the Qualifed.... + + this.expressionLengthPtr--; + QualifiedAllocationExpression qae = + (QualifiedAllocationExpression) this.expressionStack[this.expressionPtr--]; + qae.enclosingInstance = this.expressionStack[this.expressionPtr]; + this.expressionStack[this.expressionPtr] = qae; + qae.sourceStart = qae.enclosingInstance.sourceStart; +} +protected void consumeClassTypeElt() { + // ClassTypeElt ::= ClassType + pushOnAstStack(getTypeReference(0)); + /* if incomplete thrown exception list, listLength counter will not have been reset, + indicating that some items are available on the stack */ + this.listLength++; +} +protected void consumeClassTypeList() { + // ClassTypeList ::= ClassTypeList ',' ClassTypeElt + optimizedConcatNodeLists(); +} +protected void consumeCompilationUnit() { + // CompilationUnit ::= EnterCompilationUnit PackageDeclarationopt ImportDeclarationsopt + // do nothing by default +} +protected void consumeConditionalExpression(int op) { + // ConditionalExpression ::= ConditionalOrExpression '?' Expression ':' ConditionalExpression + //optimize the push/pop + + this.expressionPtr -= 2; + this.expressionLengthPtr -= 2; + this.expressionStack[this.expressionPtr] = + new ConditionalExpression( + this.expressionStack[this.expressionPtr], + this.expressionStack[this.expressionPtr + 1], + this.expressionStack[this.expressionPtr + 2]); +} +protected void consumeConstructorBlockStatements() { + // ConstructorBody ::= NestedMethod '{' ExplicitConstructorInvocation BlockStatements '}' + concatNodeLists(); // explictly add the first statement into the list of statements +} +protected void consumeConstructorBody() { + // ConstructorBody ::= NestedMethod '{' BlockStatementsopt '}' + // ConstructorBody ::= NestedMethod '{' ExplicitConstructorInvocation '}' + this.nestedMethod[this.nestedType] --; +} +protected void consumeConstructorDeclaration() { + // ConstructorDeclaration ::= ConstructorHeader ConstructorBody + + /* + astStack : MethodDeclaration statements + identifierStack : name + ==> + astStack : MethodDeclaration + identifierStack : + */ + + //must provide a default constructor call when needed + + int length; + + // pop the position of the { (body of the method) pushed in block decl + this.intPtr--; + this.intPtr--; + + //statements + this.realBlockPtr--; + ExplicitConstructorCall constructorCall = null; + Statement[] statements = null; + if ((length = this.astLengthStack[this.astLengthPtr--]) != 0) { + this.astPtr -= length; + if (this.astStack[this.astPtr + 1] instanceof ExplicitConstructorCall) { + //avoid a isSomeThing that would only be used here BUT what is faster between two alternatives ? + System.arraycopy( + this.astStack, + this.astPtr + 2, + statements = new Statement[length - 1], + 0, + length - 1); + constructorCall = (ExplicitConstructorCall) this.astStack[this.astPtr + 1]; + } else { //need to add explicitly the super(); + System.arraycopy( + this.astStack, + this.astPtr + 1, + statements = new Statement[length], + 0, + length); + constructorCall = SuperReference.implicitSuperConstructorCall(); + } + } else { + boolean insideFieldInitializer = false; + if (this.diet) { + for (int i = this.nestedType; i > 0; i--){ + if (this.variablesCounter[i] > 0) { + insideFieldInitializer = true; + break; + } + } + } + + if (!this.diet || insideFieldInitializer){ + // add it only in non-diet mode, if diet_bodies, then constructor call will be added elsewhere. + constructorCall = SuperReference.implicitSuperConstructorCall(); + } + } + + // now we know that the top of stack is a constructorDeclaration + ConstructorDeclaration cd = (ConstructorDeclaration) this.astStack[this.astPtr]; + cd.constructorCall = constructorCall; + cd.statements = statements; + + //highlight of the implicit call on the method name + if (constructorCall != null && cd.constructorCall.sourceEnd == 0) { + cd.constructorCall.sourceEnd = cd.sourceEnd; + cd.constructorCall.sourceStart = cd.sourceStart; + } + + if (!this.diet && (statements == null && constructorCall.isImplicitSuper())) { + if (!containsComment(cd.bodyStart, this.endPosition)) { + cd.bits |= ASTNode.UndocumentedEmptyBlockMASK; + } + } + + //watch for } that could be given as a unicode ! ( u007D is '}' ) + // store the endPosition (position just before the '}') in case there is + // a trailing comment behind the end of the method + cd.bodyEnd = this.endPosition; + cd.declarationSourceEnd = flushCommentsDefinedPriorTo(this.endStatementPosition); +} + +protected void consumeInvalidConstructorDeclaration() { + // ConstructorDeclaration ::= ConstructorHeader ';' + // now we know that the top of stack is a constructorDeclaration + ConstructorDeclaration cd = (ConstructorDeclaration) this.astStack[this.astPtr]; + + cd.bodyEnd = this.endPosition; // position just before the trailing semi-colon + cd.declarationSourceEnd = flushCommentsDefinedPriorTo(this.endStatementPosition); + // report the problem and continue the parsing - narrowing the problem onto the method + + cd.modifiers |= AccSemicolonBody; // remember semi-colon body +} +protected void consumeConstructorHeader() { + // ConstructorHeader ::= ConstructorHeaderName MethodHeaderParameters MethodHeaderThrowsClauseopt + + AbstractMethodDeclaration method = (AbstractMethodDeclaration)this.astStack[this.astPtr]; + + if (this.currentToken == TokenNameLBRACE){ + method.bodyStart = this.scanner.currentPosition; + } + // recovery + if (this.currentElement != null){ + if (this.currentToken == TokenNameSEMICOLON){ // for invalid constructors + method.modifiers |= AccSemicolonBody; + method.declarationSourceEnd = this.scanner.currentPosition-1; + method.bodyEnd = this.scanner.currentPosition-1; + if (this.currentElement.parseTree() == method && this.currentElement.parent != null) { + this.currentElement = this.currentElement.parent; + } + } + this.restartRecovery = true; // used to avoid branching back into the regular automaton + } +} +protected void consumeConstructorHeaderName() { + + /* recovering - might be an empty message send */ + if (this.currentElement != null){ + if (this.lastIgnoredToken == TokenNamenew){ // was an allocation expression + this.lastCheckPoint = this.scanner.startPosition; // force to restart at this exact position + this.restartRecovery = true; + return; + } + } + + // ConstructorHeaderName ::= Modifiersopt 'Identifier' '(' + ConstructorDeclaration cd = new ConstructorDeclaration(this.compilationUnit.compilationResult); + + //name -- this is not really revelant but we do ..... + cd.selector = this.identifierStack[this.identifierPtr]; + long selectorSource = this.identifierPositionStack[this.identifierPtr--]; + this.identifierLengthPtr--; + + //modifiers + cd.declarationSourceStart = this.intStack[this.intPtr--]; + cd.modifiers = this.intStack[this.intPtr--]; + // javadoc + cd.javadoc = this.javadoc; + this.javadoc = null; + + //highlight starts at the selector starts + cd.sourceStart = (int) (selectorSource >>> 32); + pushOnAstStack(cd); + cd.sourceEnd = this.lParenPos; + cd.bodyStart = this.lParenPos+1; + this.listLength = 0; // initialize listLength before reading parameters/throws + + // recovery + if (this.currentElement != null){ + this.lastCheckPoint = cd.bodyStart; + if ((this.currentElement instanceof RecoveredType && this.lastIgnoredToken != TokenNameDOT) + || cd.modifiers != 0){ + this.currentElement = this.currentElement.add(cd, 0); + this.lastIgnoredToken = -1; + } + } +} +protected void consumeDefaultLabel() { + // SwitchLabel ::= 'default' ':' + pushOnAstStack(new CaseStatement(null, this.intStack[this.intPtr--], this.intStack[this.intPtr--])); +} +protected void consumeDefaultModifiers() { + checkComment(); // might update modifiers with AccDeprecated + pushOnIntStack(this.modifiers); // modifiers + pushOnIntStack( + this.modifiersSourceStart >= 0 ? this.modifiersSourceStart : this.scanner.startPosition); + resetModifiers(); +} +protected void consumeDiet() { + // Diet ::= $empty + checkComment(); + pushOnIntStack(this.modifiersSourceStart); // push the start position of a javadoc comment if there is one + resetModifiers(); + jumpOverMethodBody(); +} +protected void consumeDims() { + // Dims ::= DimsLoop + pushOnIntStack(this.dimensions); + this.dimensions = 0; +} +protected void consumeDimWithOrWithOutExpr() { + // DimWithOrWithOutExpr ::= '[' ']' + pushOnExpressionStack(null); + + if(this.currentElement != null && this.currentToken == TokenNameLBRACE) { + this.ignoreNextOpeningBrace = true; + this.currentElement.bracketBalance++; + } +} +protected void consumeDimWithOrWithOutExprs() { + // DimWithOrWithOutExprs ::= DimWithOrWithOutExprs DimWithOrWithOutExpr + concatExpressionLists(); +} +protected void consumeEmptyArgumentListopt() { + // ArgumentListopt ::= $empty + pushOnExpressionStackLengthStack(0); +} +protected void consumeEmptyArrayInitializer() { + // ArrayInitializer ::= '{' ,opt '}' + arrayInitializer(0); +} +protected void consumeEmptyArrayInitializeropt() { + // ArrayInitializeropt ::= $empty + pushOnExpressionStackLengthStack(0); +} +protected void consumeEmptyBlockStatementsopt() { + // BlockStatementsopt ::= $empty + pushOnAstLengthStack(0); +} +protected void consumeEmptyCatchesopt() { + // Catchesopt ::= $empty + pushOnAstLengthStack(0); +} +protected void consumeEmptyClassBodyDeclarationsopt() { + // ClassBodyDeclarationsopt ::= $empty + pushOnAstLengthStack(0); +} +protected void consumeEmptyClassMemberDeclaration() { + // ClassMemberDeclaration ::= ';' + pushOnAstLengthStack(0); + problemReporter().superfluousSemicolon(this.endPosition+1, this.endStatementPosition); + flushCommentsDefinedPriorTo(this.endStatementPosition); +} +protected void consumeEmptyDimsopt() { + // Dimsopt ::= $empty + pushOnIntStack(0); +} +protected void consumeEmptyExpression() { + // Expressionopt ::= $empty + pushOnExpressionStackLengthStack(0); +} +protected void consumeEmptyForInitopt() { + // ForInitopt ::= $empty + pushOnAstLengthStack(0); +} +protected void consumeEmptyForUpdateopt() { + // ForUpdateopt ::= $empty + pushOnExpressionStackLengthStack(0); +} +protected void consumeEmptyImportDeclarationsopt() { + // ImportDeclarationsopt ::= $empty + pushOnAstLengthStack(0); +} +protected void consumeEmptyInterfaceMemberDeclaration() { + // InterfaceMemberDeclaration ::= ';' + pushOnAstLengthStack(0); +} +protected void consumeEmptyInterfaceMemberDeclarationsopt() { + // InterfaceMemberDeclarationsopt ::= $empty + pushOnAstLengthStack(0); +} +protected void consumeEmptyStatement() { + // EmptyStatement ::= ';' + if (this.scanner.source[this.endStatementPosition] == ';') { + pushOnAstStack(new EmptyStatement(this.endStatementPosition, this.endStatementPosition)); + } else { + // we have a Unicode for the ';' (/u003B) + pushOnAstStack(new EmptyStatement(this.endStatementPosition - 5, this.endStatementPosition)); + } +} +protected void consumeEmptySwitchBlock() { + // SwitchBlock ::= '{' '}' + pushOnAstLengthStack(0); +} +protected void consumeEmptyTypeDeclaration() { + // TypeDeclaration ::= ';' + pushOnAstLengthStack(0); + problemReporter().superfluousSemicolon(this.endPosition+1, this.endStatementPosition); + flushCommentsDefinedPriorTo(this.endStatementPosition); +} +protected void consumeEmptyTypeDeclarationsopt() { + // TypeDeclarationsopt ::= $empty + pushOnAstLengthStack(0); +} +protected void consumeEnterAnonymousClassBody() { + // EnterAnonymousClassBody ::= $empty + QualifiedAllocationExpression alloc; + TypeDeclaration anonymousType = new TypeDeclaration(this.compilationUnit.compilationResult); + anonymousType.name = TypeDeclaration.ANONYMOUS_EMPTY_NAME; + anonymousType.bits |= ASTNode.AnonymousAndLocalMask; + alloc = anonymousType.allocation = new QualifiedAllocationExpression(anonymousType); + markEnclosingMemberWithLocalType(); + pushOnAstStack(anonymousType); + + alloc.sourceEnd = this.rParenPos; //the position has been stored explicitly + int argumentLength; + if ((argumentLength = this.expressionLengthStack[this.expressionLengthPtr--]) != 0) { + this.expressionPtr -= argumentLength; + System.arraycopy( + this.expressionStack, + this.expressionPtr + 1, + alloc.arguments = new Expression[argumentLength], + 0, + argumentLength); + } + alloc.type = getTypeReference(0); + + anonymousType.sourceEnd = alloc.sourceEnd; + //position at the type while it impacts the anonymous declaration + anonymousType.sourceStart = anonymousType.declarationSourceStart = alloc.type.sourceStart; + alloc.sourceStart = this.intStack[this.intPtr--]; + pushOnExpressionStack(alloc); + + anonymousType.bodyStart = this.scanner.currentPosition; + this.listLength = 0; // will be updated when reading super-interfaces + // recovery + if (this.currentElement != null){ + this.lastCheckPoint = anonymousType.bodyStart; + this.currentElement = this.currentElement.add(anonymousType, 0); + this.currentToken = 0; // opening brace already taken into account + this.lastIgnoredToken = -1; + } +} +protected void consumeEnterCompilationUnit() { + // EnterCompilationUnit ::= $empty + // do nothing by default +} +protected void consumeEnterVariable() { + // EnterVariable ::= $empty + // do nothing by default + + char[] identifierName = this.identifierStack[this.identifierPtr]; + long namePosition = this.identifierPositionStack[this.identifierPtr]; + int extendedDimension = this.intStack[this.intPtr--]; + AbstractVariableDeclaration declaration; + // create the ast node + boolean isLocalDeclaration = this.nestedMethod[this.nestedType] != 0; + if (isLocalDeclaration) { + // create the local variable declarations + declaration = + this.createLocalDeclaration(identifierName, (int) (namePosition >>> 32), (int) namePosition); + } else { + // create the field declaration + declaration = + this.createFieldDeclaration(identifierName, (int) (namePosition >>> 32), (int) namePosition); + } + + this.identifierPtr--; + this.identifierLengthPtr--; + TypeReference type; + int variableIndex = this.variablesCounter[this.nestedType]; + int typeDim = 0; + if (variableIndex == 0) { + // first variable of the declaration (FieldDeclaration or LocalDeclaration) + if (isLocalDeclaration) { + declaration.declarationSourceStart = this.intStack[this.intPtr--]; + declaration.modifiers = this.intStack[this.intPtr--]; + type = getTypeReference(typeDim = this.intStack[this.intPtr--]); // type dimension + if (declaration.declarationSourceStart == -1) { + // this is true if there is no modifiers for the local variable declaration + declaration.declarationSourceStart = type.sourceStart; + } + pushOnAstStack(type); + } else { + type = getTypeReference(typeDim = this.intStack[this.intPtr--]); // type dimension + pushOnAstStack(type); + declaration.declarationSourceStart = this.intStack[this.intPtr--]; + declaration.modifiers = this.intStack[this.intPtr--]; + + // Store javadoc only on first declaration as it is the same for all ones + FieldDeclaration fieldDeclaration = (FieldDeclaration) declaration; + fieldDeclaration.javadoc = this.javadoc; + this.javadoc = null; + } + } else { + type = (TypeReference) this.astStack[this.astPtr - variableIndex]; + typeDim = type.dimensions(); + AbstractVariableDeclaration previousVariable = + (AbstractVariableDeclaration) this.astStack[this.astPtr]; + declaration.declarationSourceStart = previousVariable.declarationSourceStart; + declaration.modifiers = previousVariable.modifiers; + } + + if (extendedDimension == 0) { + declaration.type = type; + } else { + int dimension = typeDim + extendedDimension; + //on the identifierLengthStack there is the information about the type.... + int baseType; + if ((baseType = this.identifierLengthStack[this.identifierLengthPtr + 1]) < 0) { + //it was a baseType + int typeSourceStart = type.sourceStart; + int typeSourceEnd = type.sourceEnd; + type = TypeReference.baseTypeReference(-baseType, dimension); + type.sourceStart = typeSourceStart; + type.sourceEnd = typeSourceEnd; + declaration.type = type; + } else { + declaration.type = this.copyDims(type, dimension); + } + } + this.variablesCounter[this.nestedType]++; + pushOnAstStack(declaration); + // recovery + if (this.currentElement != null) { + if (!(this.currentElement instanceof RecoveredType) + && (this.currentToken == TokenNameDOT + //|| declaration.modifiers != 0 + || (this.scanner.getLineNumber(declaration.type.sourceStart) + != this.scanner.getLineNumber((int) (namePosition >>> 32))))){ + this.lastCheckPoint = (int) (namePosition >>> 32); + this.restartRecovery = true; + return; + } + if (isLocalDeclaration){ + LocalDeclaration localDecl = (LocalDeclaration) this.astStack[this.astPtr]; + this.lastCheckPoint = localDecl.sourceEnd + 1; + this.currentElement = this.currentElement.add(localDecl, 0); + } else { + FieldDeclaration fieldDecl = (FieldDeclaration) this.astStack[this.astPtr]; + this.lastCheckPoint = fieldDecl.sourceEnd + 1; + this.currentElement = this.currentElement.add(fieldDecl, 0); + } + this.lastIgnoredToken = -1; + } +} +protected void consumeEqualityExpression(int op) { + // EqualityExpression ::= EqualityExpression '==' RelationalExpression + // EqualityExpression ::= EqualityExpression '!=' RelationalExpression + + //optimize the push/pop + + this.expressionPtr--; + this.expressionLengthPtr--; + this.expressionStack[this.expressionPtr] = + new EqualExpression( + this.expressionStack[this.expressionPtr], + this.expressionStack[this.expressionPtr + 1], + op); +} +protected void consumeExitTryBlock() { + //ExitTryBlock ::= $empty + if(this.currentElement != null) { + this.restartRecovery = true; + } +} +protected void consumeExitVariableWithInitialization() { + // ExitVariableWithInitialization ::= $empty + // do nothing by default + this.expressionLengthPtr--; + AbstractVariableDeclaration variableDecl = (AbstractVariableDeclaration) this.astStack[this.astPtr]; + variableDecl.initialization = this.expressionStack[this.expressionPtr--]; + // we need to update the declarationSourceEnd of the local variable declaration to the + // source end position of the initialization expression + variableDecl.declarationSourceEnd = variableDecl.initialization.sourceEnd; + variableDecl.declarationEnd = variableDecl.initialization.sourceEnd; + + this.recoveryExitFromVariable(); +} +protected void consumeExitVariableWithoutInitialization() { + // ExitVariableWithoutInitialization ::= $empty + // do nothing by default + + AbstractVariableDeclaration variableDecl = (AbstractVariableDeclaration) this.astStack[this.astPtr]; + variableDecl.declarationSourceEnd = variableDecl.declarationEnd; + + this.recoveryExitFromVariable(); +} +protected void consumeExplicitConstructorInvocation(int flag, int recFlag) { + + /* flag allows to distinguish 3 cases : + (0) : + ExplicitConstructorInvocation ::= 'this' '(' ArgumentListopt ')' ';' + ExplicitConstructorInvocation ::= 'super' '(' ArgumentListopt ')' ';' + (1) : + ExplicitConstructorInvocation ::= Primary '.' 'super' '(' ArgumentListopt ')' ';' + ExplicitConstructorInvocation ::= Primary '.' 'this' '(' ArgumentListopt ')' ';' + (2) : + ExplicitConstructorInvocation ::= Name '.' 'super' '(' ArgumentListopt ')' ';' + ExplicitConstructorInvocation ::= Name '.' 'this' '(' ArgumentListopt ')' ';' + */ + int startPosition = this.intStack[this.intPtr--]; + ExplicitConstructorCall ecc = new ExplicitConstructorCall(recFlag); + int length; + if ((length = this.expressionLengthStack[this.expressionLengthPtr--]) != 0) { + this.expressionPtr -= length; + System.arraycopy(this.expressionStack, this.expressionPtr + 1, ecc.arguments = new Expression[length], 0, length); + } + switch (flag) { + case 0 : + ecc.sourceStart = startPosition; + break; + case 1 : + this.expressionLengthPtr--; + ecc.sourceStart = (ecc.qualification = this.expressionStack[this.expressionPtr--]).sourceStart; + break; + case 2 : + ecc.sourceStart = (ecc.qualification = getUnspecifiedReferenceOptimized()).sourceStart; + break; + } + pushOnAstStack(ecc); + ecc.sourceEnd = this.endPosition; +} +protected void consumeExpressionStatement() { + // ExpressionStatement ::= StatementExpression ';' + this.expressionLengthPtr--; + pushOnAstStack(this.expressionStack[this.expressionPtr--]); +} +protected void consumeFieldAccess(boolean isSuperAccess) { + // FieldAccess ::= Primary '.' 'Identifier' + // FieldAccess ::= 'super' '.' 'Identifier' + + FieldReference fr = + new FieldReference( + this.identifierStack[this.identifierPtr], + this.identifierPositionStack[this.identifierPtr--]); + this.identifierLengthPtr--; + if (isSuperAccess) { + //considerates the fieldReference beginning at the 'super' .... + fr.sourceStart = this.intStack[this.intPtr--]; + fr.receiver = new SuperReference(fr.sourceStart, this.endPosition); + pushOnExpressionStack(fr); + } else { + //optimize push/pop + if ((fr.receiver = this.expressionStack[this.expressionPtr]).isThis()) { + //fieldreference begins at the this + fr.sourceStart = fr.receiver.sourceStart; + } + this.expressionStack[this.expressionPtr] = fr; + } +} +protected void consumeFieldDeclaration() { + // See consumeLocalVariableDeclarationDefaultModifier() in case of change: duplicated code + // FieldDeclaration ::= Modifiersopt Type VariableDeclarators ';' + + /* + astStack : + expressionStack: Expression Expression ...... Expression + identifierStack : type identifier identifier ...... identifier + intStack : typeDim dim dim dim + ==> + astStack : FieldDeclaration FieldDeclaration ...... FieldDeclaration + expressionStack : + identifierStack : + intStack : + + */ + int variableDeclaratorsCounter = this.astLengthStack[this.astLengthPtr]; + + for (int i = variableDeclaratorsCounter - 1; i >= 0; i--) { + FieldDeclaration fieldDeclaration = (FieldDeclaration) this.astStack[this.astPtr - i]; + fieldDeclaration.declarationSourceEnd = this.endStatementPosition; + fieldDeclaration.declarationEnd = this.endStatementPosition; // semi-colon included + } + + updateSourceDeclarationParts(variableDeclaratorsCounter); + int endPos = flushCommentsDefinedPriorTo(this.endStatementPosition); + if (endPos != this.endStatementPosition) { + for (int i = 0; i < variableDeclaratorsCounter; i++) { + FieldDeclaration fieldDeclaration = (FieldDeclaration) this.astStack[this.astPtr - i]; + fieldDeclaration.declarationSourceEnd = endPos; + } + } + // update the astStack, astPtr and astLengthStack + int startIndex = this.astPtr - this.variablesCounter[this.nestedType] + 1; + System.arraycopy( + this.astStack, + startIndex, + this.astStack, + startIndex - 1, + variableDeclaratorsCounter); + this.astPtr--; // remove the type reference + this.astLengthStack[--this.astLengthPtr] = variableDeclaratorsCounter; + + // recovery + if (this.currentElement != null) { + this.lastCheckPoint = endPos + 1; + if (this.currentElement.parent != null && this.currentElement instanceof RecoveredField){ + if (!(this.currentElement instanceof RecoveredInitializer)) { + this.currentElement = this.currentElement.parent; + } + } + this.restartRecovery = true; + } + this.variablesCounter[this.nestedType] = 0; +} +protected void consumeForceNoDiet() { + // ForceNoDiet ::= $empty + this.dietInt++; +} +protected void consumeForInit() { + // ForInit ::= StatementExpressionList + pushOnAstLengthStack(-1); +} +protected void consumeFormalParameter() { + // FormalParameter ::= Type VariableDeclaratorId ==> false + // FormalParameter ::= Modifiers Type VariableDeclaratorId ==> true + /* + astStack : + identifierStack : type identifier + intStack : dim dim + ==> + astStack : Argument + identifierStack : + intStack : + */ + + this.identifierLengthPtr--; + char[] identifierName = this.identifierStack[this.identifierPtr]; + long namePositions = this.identifierPositionStack[this.identifierPtr--]; + TypeReference type = getTypeReference(this.intStack[this.intPtr--] + this.intStack[this.intPtr--]); + int modifierPositions = this.intStack[this.intPtr--]; + this.intPtr--; + Argument arg = + new Argument( + identifierName, + namePositions, + type, + this.intStack[this.intPtr + 1] & ~AccDeprecated); // modifiers + arg.declarationSourceStart = modifierPositions; + pushOnAstStack(arg); + + /* if incomplete method header, listLength counter will not have been reset, + indicating that some arguments are available on the stack */ + this.listLength++; +} +protected void consumeFormalParameterList() { + // FormalParameterList ::= FormalParameterList ',' FormalParameter + optimizedConcatNodeLists(); +} +protected void consumeFormalParameterListopt() { + // FormalParameterListopt ::= $empty + pushOnAstLengthStack(0); +} +protected void consumeImportDeclarations() { + // ImportDeclarations ::= ImportDeclarations ImportDeclaration + optimizedConcatNodeLists(); +} +protected void consumeImportDeclarationsopt() { + // ImportDeclarationsopt ::= ImportDeclarations + int length; + if ((length = this.astLengthStack[this.astLengthPtr--]) != 0) { + this.astPtr -= length; + System.arraycopy( + this.astStack, + this.astPtr + 1, + this.compilationUnit.imports = new ImportReference[length], + 0, + length); + } +} +protected void consumeInsideCastExpression() { + // InsideCastExpression ::= $empty +} +protected void consumeInsideCastExpressionLL1() { + // InsideCastExpressionLL1 ::= $empty +} + +protected void consumeInstanceOfExpression(int op) { + // RelationalExpression ::= RelationalExpression 'instanceof' ReferenceType + //optimize the push/pop + + //by construction, no base type may be used in getTypeReference + Expression exp; + this.expressionStack[this.expressionPtr] = exp = + new InstanceOfExpression( + this.expressionStack[this.expressionPtr], + getTypeReference(this.intStack[this.intPtr--]), + op); + if (exp.sourceEnd == 0) { + //array on base type.... + exp.sourceEnd = this.scanner.startPosition - 1; + } + //the scanner is on the next token already.... +} +protected void consumeInterfaceDeclaration() { + // see consumeClassDeclaration in case of changes: duplicated code + // InterfaceDeclaration ::= InterfaceHeader InterfaceBody + int length; + if ((length = this.astLengthStack[this.astLengthPtr--]) != 0) { + //there are length declarations + //dispatch.....according to the type of the declarations + dispatchDeclarationInto(length); + } + + TypeDeclaration typeDecl = (TypeDeclaration) this.astStack[this.astPtr]; + + // mark initializers with local type mark if needed + markInitializersWithLocalType(typeDecl); + + //convert constructor that do not have the type's name into methods + typeDecl.checkConstructors(this); + + //always add (will be remove at code gen time if empty) + if (this.scanner.containsAssertKeyword) { + typeDecl.bits |= ASTNode.AddAssertionMASK; + } + typeDecl.addClinit(); + typeDecl.bodyEnd = this.endStatementPosition; + if (length == 0 && !containsComment(typeDecl.bodyStart, typeDecl.bodyEnd)) { + typeDecl.bits |= ASTNode.UndocumentedEmptyBlockMASK; + } + typeDecl.declarationSourceEnd = flushCommentsDefinedPriorTo(this.endStatementPosition); +} +protected void consumeInterfaceHeader() { + // InterfaceHeader ::= InterfaceHeaderName InterfaceHeaderExtendsopt + + TypeDeclaration typeDecl = (TypeDeclaration) this.astStack[this.astPtr]; + if (this.currentToken == TokenNameLBRACE){ + typeDecl.bodyStart = this.scanner.currentPosition; + } + if (this.currentElement != null){ + this.restartRecovery = true; // used to avoid branching back into the regular automaton + } + // flush the comments related to the interface header + this.scanner.commentPtr = -1; +} +protected void consumeInterfaceHeaderExtends() { + // InterfaceHeaderExtends ::= 'extends' InterfaceTypeList + int length = this.astLengthStack[this.astLengthPtr--]; + //super interfaces + this.astPtr -= length; + TypeDeclaration typeDecl = (TypeDeclaration) this.astStack[this.astPtr]; + System.arraycopy( + this.astStack, + this.astPtr + 1, + typeDecl.superInterfaces = new TypeReference[length], + 0, + length); + typeDecl.bodyStart = typeDecl.superInterfaces[length-1].sourceEnd + 1; + this.listLength = 0; // reset after having read super-interfaces + // recovery + if (this.currentElement != null) { + this.lastCheckPoint = typeDecl.bodyStart; + } +} +protected void consumeInterfaceHeaderName() { + // InterfaceHeaderName ::= Modifiersopt 'interface' 'Identifier' + TypeDeclaration typeDecl = new TypeDeclaration(this.compilationUnit.compilationResult); + + if (this.nestedMethod[this.nestedType] == 0) { + if (this.nestedType != 0) { + typeDecl.bits |= ASTNode.IsMemberTypeMASK; + } + } else { + // Record that the block has a declaration for local types + typeDecl.bits |= ASTNode.IsLocalTypeMASK; + markEnclosingMemberWithLocalType(); + blockReal(); + } + + //highlight the name of the type + long pos = this.identifierPositionStack[this.identifierPtr]; + typeDecl.sourceEnd = (int) pos; + typeDecl.sourceStart = (int) (pos >>> 32); + typeDecl.name = this.identifierStack[this.identifierPtr--]; + this.identifierLengthPtr--; + + //compute the declaration source too + // 'class' and 'interface' push two int positions: the beginning of the class token and its end. + // we want to keep the beginning position but get rid of the end position + // it is only used for the ClassLiteralAccess positions. + typeDecl.declarationSourceStart = this.intStack[this.intPtr--]; + this.intPtr--; // remove the end position of the class token + typeDecl.modifiersSourceStart = this.intStack[this.intPtr--]; + typeDecl.modifiers = this.intStack[this.intPtr--]; + if (typeDecl.modifiersSourceStart >= 0) { + typeDecl.declarationSourceStart = typeDecl.modifiersSourceStart; + } + typeDecl.bodyStart = typeDecl.sourceEnd + 1; + pushOnAstStack(typeDecl); + this.listLength = 0; // will be updated when reading super-interfaces + // recovery + if (this.currentElement != null){ // is recovering + this.lastCheckPoint = typeDecl.bodyStart; + this.currentElement = this.currentElement.add(typeDecl, 0); + this.lastIgnoredToken = -1; + } + // javadoc + typeDecl.javadoc = this.javadoc; + this.javadoc = null; +} +protected void consumeInterfaceMemberDeclarations() { + // InterfaceMemberDeclarations ::= InterfaceMemberDeclarations InterfaceMemberDeclaration + concatNodeLists(); +} +protected void consumeInterfaceMemberDeclarationsopt() { + // InterfaceMemberDeclarationsopt ::= NestedType InterfaceMemberDeclarations + this.nestedType--; +} +protected void consumeInterfaceType() { + // InterfaceType ::= ClassOrInterfaceType + pushOnAstStack(getTypeReference(0)); + /* if incomplete type header, listLength counter will not have been reset, + indicating that some interfaces are available on the stack */ + this.listLength++; +} +protected void consumeInterfaceTypeList() { + // InterfaceTypeList ::= InterfaceTypeList ',' InterfaceType + optimizedConcatNodeLists(); +} +protected void consumeLeftParen() { + // PushLPAREN ::= '(' + pushOnIntStack(this.lParenPos); +} +protected void consumeLocalVariableDeclaration() { + // LocalVariableDeclaration ::= Modifiers Type VariableDeclarators ';' + + /* + astStack : + expressionStack: Expression Expression ...... Expression + identifierStack : type identifier identifier ...... identifier + intStack : typeDim dim dim dim + ==> + astStack : FieldDeclaration FieldDeclaration ...... FieldDeclaration + expressionStack : + identifierStack : + intStack : + + */ + int variableDeclaratorsCounter = this.astLengthStack[this.astLengthPtr]; + + // update the astStack, astPtr and astLengthStack + int startIndex = this.astPtr - this.variablesCounter[this.nestedType] + 1; + System.arraycopy( + this.astStack, + startIndex, + this.astStack, + startIndex - 1, + variableDeclaratorsCounter); + this.astPtr--; // remove the type reference + this.astLengthStack[--this.astLengthPtr] = variableDeclaratorsCounter; + this.variablesCounter[this.nestedType] = 0; +} +protected void consumeLocalVariableDeclarationStatement() { + // LocalVariableDeclarationStatement ::= LocalVariableDeclaration ';' + // see blockReal in case of change: duplicated code + // increment the amount of declared variables for this block + this.realBlockStack[this.realBlockPtr]++; + + // update source end to include the semi-colon + int variableDeclaratorsCounter = this.astLengthStack[this.astLengthPtr]; + for (int i = variableDeclaratorsCounter - 1; i >= 0; i--) { + LocalDeclaration localDeclaration = (LocalDeclaration) this.astStack[this.astPtr - i]; + localDeclaration.declarationSourceEnd = this.endStatementPosition; + localDeclaration.declarationEnd = this.endStatementPosition; // semi-colon included + } + +} +protected void consumeMethodBody() { + // MethodBody ::= NestedMethod '{' BlockStatementsopt '}' + this.nestedMethod[this.nestedType] --; +} +protected void consumeMethodDeclaration(boolean isNotAbstract) { + // MethodDeclaration ::= MethodHeader MethodBody + // AbstractMethodDeclaration ::= MethodHeader ';' + + /* + astStack : modifiers arguments throws statements + identifierStack : type name + intStack : dim dim dim + ==> + astStack : MethodDeclaration + identifierStack : + intStack : + */ + + int length; + if (isNotAbstract) { + // pop the position of the { (body of the method) pushed in block decl + this.intPtr--; + this.intPtr--; + } + + int explicitDeclarations = 0; + Statement[] statements = null; + if (isNotAbstract) { + //statements + explicitDeclarations = this.realBlockStack[this.realBlockPtr--]; + if ((length = this.astLengthStack[this.astLengthPtr--]) != 0) { + System.arraycopy( + this.astStack, + (this.astPtr -= length) + 1, + statements = new Statement[length], + 0, + length); + } + } + + // now we know that we have a method declaration at the top of the ast stack + MethodDeclaration md = (MethodDeclaration) this.astStack[this.astPtr]; + md.statements = statements; + md.explicitDeclarations = explicitDeclarations; + + // cannot be done in consumeMethodHeader because we have no idea whether or not there + // is a body when we reduce the method header + if (!isNotAbstract) { //remember the fact that the method has a semicolon body + md.modifiers |= AccSemicolonBody; + } else { + if (!this.diet && statements == null) { + if (!containsComment(md.bodyStart, this.endPosition)) { + md.bits |= ASTNode.UndocumentedEmptyBlockMASK; + } + } + } + // store the endPosition (position just before the '}') in case there is + // a trailing comment behind the end of the method + md.bodyEnd = this.endPosition; + md.declarationSourceEnd = flushCommentsDefinedPriorTo(this.endStatementPosition); +} +protected void consumeMethodHeader() { + // MethodHeader ::= MethodHeaderName MethodHeaderParameters MethodHeaderExtendedDims ThrowsClauseopt + // retrieve end position of method declarator + AbstractMethodDeclaration method = (AbstractMethodDeclaration)this.astStack[this.astPtr]; + + if (this.currentToken == TokenNameLBRACE){ + method.bodyStart = this.scanner.currentPosition; + } + // recovery + if (this.currentElement != null){ + if (this.currentToken == TokenNameSEMICOLON){ + method.modifiers |= AccSemicolonBody; + method.declarationSourceEnd = this.scanner.currentPosition-1; + method.bodyEnd = this.scanner.currentPosition-1; + if (this.currentElement.parseTree() == method && this.currentElement.parent != null) { + this.currentElement = this.currentElement.parent; + } + } + this.restartRecovery = true; // used to avoid branching back into the regular automaton + } +} +protected void consumeMethodHeaderExtendedDims() { + // MethodHeaderExtendedDims ::= Dimsopt + // now we update the returnType of the method + MethodDeclaration md = (MethodDeclaration) this.astStack[this.astPtr]; + int extendedDims = this.intStack[this.intPtr--]; + if (extendedDims != 0) { + TypeReference returnType = md.returnType; + md.sourceEnd = this.endPosition; + int dims = returnType.dimensions() + extendedDims; + int baseType; + if ((baseType = this.identifierLengthStack[this.identifierLengthPtr + 1]) < 0) { + //it was a baseType + int sourceStart = returnType.sourceStart; + int sourceEnd = returnType.sourceEnd; + returnType = TypeReference.baseTypeReference(-baseType, dims); + returnType.sourceStart = sourceStart; + returnType.sourceEnd = sourceEnd; + md.returnType = returnType; + } else { + md.returnType = this.copyDims(md.returnType, dims); + } + if (this.currentToken == TokenNameLBRACE){ + md.bodyStart = this.endPosition + 1; + } + // recovery + if (this.currentElement != null){ + this.lastCheckPoint = md.bodyStart; + } + } +} +protected void consumeMethodHeaderName() { + // MethodHeaderName ::= Modifiersopt Type 'Identifier' '(' + MethodDeclaration md = new MethodDeclaration(this.compilationUnit.compilationResult); + + //name + md.selector = this.identifierStack[this.identifierPtr]; + long selectorSource = this.identifierPositionStack[this.identifierPtr--]; + this.identifierLengthPtr--; + //type + md.returnType = getTypeReference(this.intStack[this.intPtr--]); + //modifiers + md.declarationSourceStart = this.intStack[this.intPtr--]; + md.modifiers = this.intStack[this.intPtr--]; + // javadoc + md.javadoc = this.javadoc; + this.javadoc = null; + + //highlight starts at selector start + md.sourceStart = (int) (selectorSource >>> 32); + pushOnAstStack(md); + md.sourceEnd = this.lParenPos; + md.bodyStart = this.lParenPos+1; + this.listLength = 0; // initialize listLength before reading parameters/throws + + // recovery + if (this.currentElement != null){ + if (this.currentElement instanceof RecoveredType + //|| md.modifiers != 0 + || (this.scanner.getLineNumber(md.returnType.sourceStart) + == this.scanner.getLineNumber(md.sourceStart))){ + this.lastCheckPoint = md.bodyStart; + this.currentElement = this.currentElement.add(md, 0); + this.lastIgnoredToken = -1; + } else { + this.lastCheckPoint = md.sourceStart; + this.restartRecovery = true; + } + } +} +protected void consumeMethodHeaderParameters() { + // MethodHeaderParameters ::= FormalParameterListopt ')' + int length = this.astLengthStack[this.astLengthPtr--]; + this.astPtr -= length; + AbstractMethodDeclaration md = (AbstractMethodDeclaration) this.astStack[this.astPtr]; + md.sourceEnd = this.rParenPos; + //arguments + if (length != 0) { + System.arraycopy( + this.astStack, + this.astPtr + 1, + md.arguments = new Argument[length], + 0, + length); + } + md.bodyStart = this.rParenPos+1; + this.listLength = 0; // reset listLength after having read all parameters + // recovery + if (this.currentElement != null){ + this.lastCheckPoint = md.bodyStart; + if (this.currentElement.parseTree() == md) return; + + // might not have been attached yet - in some constructor scenarii + if (md.isConstructor()){ + if ((length != 0) + || (this.currentToken == TokenNameLBRACE) + || (this.currentToken == TokenNamethrows)){ + this.currentElement = this.currentElement.add(md, 0); + this.lastIgnoredToken = -1; + } + } + } +} +protected void consumeMethodHeaderThrowsClause() { + // MethodHeaderThrowsClause ::= 'throws' ClassTypeList + int length = this.astLengthStack[this.astLengthPtr--]; + this.astPtr -= length; + AbstractMethodDeclaration md = (AbstractMethodDeclaration) this.astStack[this.astPtr]; + System.arraycopy( + this.astStack, + this.astPtr + 1, + md.thrownExceptions = new TypeReference[length], + 0, + length); + md.sourceEnd = md.thrownExceptions[length-1].sourceEnd; + md.bodyStart = md.thrownExceptions[length-1].sourceEnd + 1; + this.listLength = 0; // reset listLength after having read all thrown exceptions + // recovery + if (this.currentElement != null){ + this.lastCheckPoint = md.bodyStart; + } +} +protected void consumeMethodInvocationName() { + // MethodInvocation ::= Name '(' ArgumentListopt ')' + + // when the name is only an identifier...we have a message send to "this" (implicit) + + MessageSend m = newMessageSend(); + m.sourceEnd = this.rParenPos; + m.sourceStart = + (int) ((m.nameSourcePosition = this.identifierPositionStack[this.identifierPtr]) >>> 32); + m.selector = this.identifierStack[this.identifierPtr--]; + if (this.identifierLengthStack[this.identifierLengthPtr] == 1) { + m.receiver = ThisReference.implicitThis(); + this.identifierLengthPtr--; + } else { + this.identifierLengthStack[this.identifierLengthPtr]--; + m.receiver = getUnspecifiedReference(); + m.sourceStart = m.receiver.sourceStart; + } + pushOnExpressionStack(m); +} +protected void consumeMethodInvocationPrimary() { + //optimize the push/pop + //MethodInvocation ::= Primary '.' 'Identifier' '(' ArgumentListopt ')' + + MessageSend m = newMessageSend(); + m.sourceStart = + (int) ((m.nameSourcePosition = this.identifierPositionStack[this.identifierPtr]) >>> 32); + m.selector = this.identifierStack[this.identifierPtr--]; + this.identifierLengthPtr--; + m.receiver = this.expressionStack[this.expressionPtr]; + m.sourceStart = m.receiver.sourceStart; + m.sourceEnd = this.rParenPos; + this.expressionStack[this.expressionPtr] = m; +} +protected void consumeMethodInvocationSuper() { + // MethodInvocation ::= 'super' '.' 'Identifier' '(' ArgumentListopt ')' + + MessageSend m = newMessageSend(); + m.sourceStart = this.intStack[this.intPtr--]; + m.sourceEnd = this.rParenPos; + m.nameSourcePosition = this.identifierPositionStack[this.identifierPtr]; + m.selector = this.identifierStack[this.identifierPtr--]; + this.identifierLengthPtr--; + m.receiver = new SuperReference(m.sourceStart, this.endPosition); + pushOnExpressionStack(m); +} +protected void consumeModifiers() { + int savedModifiersSourceStart = this.modifiersSourceStart; + checkComment(); // might update modifiers with AccDeprecated + pushOnIntStack(this.modifiers); // modifiers + if (this.modifiersSourceStart >= savedModifiersSourceStart) { + this.modifiersSourceStart = savedModifiersSourceStart; + } + pushOnIntStack(this.modifiersSourceStart); + resetModifiers(); +} +protected void consumeNestedMethod() { + // NestedMethod ::= $empty + jumpOverMethodBody(); + this.nestedMethod[this.nestedType] ++; + pushOnIntStack(this.scanner.currentPosition); + consumeOpenBlock(); +} +protected void consumeNestedType() { + // NestedType ::= $empty + int length = this.nestedMethod.length; + if (++this.nestedType >= length) { + System.arraycopy( + this.nestedMethod, 0, + this.nestedMethod = new int[length + 30], 0, + length); + // increase the size of the variablesCounter as well. It has to be consistent with the size of the nestedMethod collection + System.arraycopy( + this.variablesCounter, 0, + this.variablesCounter = new int[length + 30], 0, + length); + } + this.nestedMethod[this.nestedType] = 0; + this.variablesCounter[this.nestedType] = 0; +} +protected void consumeOneDimLoop() { + // OneDimLoop ::= '[' ']' + this.dimensions++; +} +protected void consumeOnlySynchronized() { + // OnlySynchronized ::= 'synchronized' + pushOnIntStack(this.synchronizedBlockSourceStart); + resetModifiers(); +} +protected void consumeOpenBlock() { + // OpenBlock ::= $empty + + pushOnIntStack(this.scanner.startPosition); + int stackLength = this.realBlockStack.length; + if (++this.realBlockPtr >= stackLength) { + System.arraycopy( + this.realBlockStack, 0, + this.realBlockStack = new int[stackLength + StackIncrement], 0, + stackLength); + } + this.realBlockStack[this.realBlockPtr] = 0; +} +protected void consumePackageDeclaration() { + // PackageDeclaration ::= 'package' Name ';' + /* build an ImportRef build from the last name + stored in the identifier stack. */ + + ImportReference impt = this.compilationUnit.currentPackage; + // flush comments defined prior to import statements + impt.declarationEnd = this.endStatementPosition; + impt.declarationSourceEnd = this.flushCommentsDefinedPriorTo(impt.declarationSourceEnd); +} +protected void consumePackageDeclarationName() { + // PackageDeclarationName ::= 'package' Name + /* build an ImportRef build from the last name + stored in the identifier stack. */ + + ImportReference impt; + int length; + char[][] tokens = + new char[length = this.identifierLengthStack[this.identifierLengthPtr--]][]; + this.identifierPtr -= length; + long[] positions = new long[length]; + System.arraycopy(this.identifierStack, ++this.identifierPtr, tokens, 0, length); + System.arraycopy( + this.identifierPositionStack, + this.identifierPtr--, + positions, + 0, + length); + this.compilationUnit.currentPackage = + impt = new ImportReference(tokens, positions, true, AccDefault); + + if (this.currentToken == TokenNameSEMICOLON){ + impt.declarationSourceEnd = this.scanner.currentPosition - 1; + } else { + impt.declarationSourceEnd = impt.sourceEnd; + } + impt.declarationEnd = impt.declarationSourceEnd; + //endPosition is just before the ; + impt.declarationSourceStart = this.intStack[this.intPtr--]; + + // recovery + if (this.currentElement != null){ + this.lastCheckPoint = impt.declarationSourceEnd+1; + this.restartRecovery = true; // used to avoid branching back into the regular automaton + } +} +protected void consumePostfixExpression() { + // PostfixExpression ::= Name + pushOnExpressionStack(getUnspecifiedReferenceOptimized()); +} +protected void consumePrimaryNoNewArray() { + // PrimaryNoNewArray ::= PushLPAREN Expression PushRPAREN + final Expression parenthesizedExpression = this.expressionStack[this.expressionPtr]; + updateSourcePosition(parenthesizedExpression); + int numberOfParenthesis = (parenthesizedExpression.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT; + parenthesizedExpression.bits &= ~ASTNode.ParenthesizedMASK; + parenthesizedExpression.bits |= (numberOfParenthesis + 1) << ASTNode.ParenthesizedSHIFT; +} +protected void consumePrimaryNoNewArrayArrayType() { + // PrimaryNoNewArray ::= ArrayType '.' 'class' + this.intPtr--; + pushOnExpressionStack( + new ClassLiteralAccess(this.intStack[this.intPtr--], + getTypeReference(this.intStack[this.intPtr--]))); +} +protected void consumePrimaryNoNewArrayName() { + // PrimaryNoNewArray ::= Name '.' 'class' + this.intPtr--; + pushOnExpressionStack( + new ClassLiteralAccess(this.intStack[this.intPtr--], + getTypeReference(0))); +} +protected void consumePrimaryNoNewArrayNameSuper() { + // PrimaryNoNewArray ::= Name '.' 'super' + pushOnExpressionStack( + new QualifiedSuperReference( + getTypeReference(0), + this.intStack[this.intPtr--], + this.endPosition)); +} +protected void consumePrimaryNoNewArrayNameThis() { + // PrimaryNoNewArray ::= Name '.' 'this' + pushOnExpressionStack( + new QualifiedThisReference( + getTypeReference(0), + this.intStack[this.intPtr--], + this.endPosition)); +} +protected void consumePrimaryNoNewArrayPrimitiveType() { + // PrimaryNoNewArray ::= PrimitiveType '.' 'class' + this.intPtr--; + pushOnExpressionStack( + new ClassLiteralAccess(this.intStack[this.intPtr--], + getTypeReference(0))); +} +protected void consumePrimaryNoNewArrayThis() { + // PrimaryNoNewArray ::= 'this' + pushOnExpressionStack(new ThisReference(this.intStack[this.intPtr--], this.endPosition)); +} +protected void consumePrimitiveType() { + // Type ::= PrimitiveType + pushOnIntStack(0); +} +protected void consumePushModifiers() { + pushOnIntStack(this.modifiers); // modifiers + pushOnIntStack(this.modifiersSourceStart); + resetModifiers(); +} +protected void consumePushPosition() { + // for source managment purpose + // PushPosition ::= $empty + pushOnIntStack(this.endPosition); +} +protected void consumeQualifiedName() { + // QualifiedName ::= Name '.' SimpleName + /*back from the recursive loop of QualifiedName. + Updates identifier length into the length stack*/ + + this.identifierLengthStack[--this.identifierLengthPtr]++; +} +protected void consumeReferenceType() { + // ReferenceType ::= ClassOrInterfaceType + pushOnIntStack(0); +} +protected void consumeRestoreDiet() { + // RestoreDiet ::= $empty + this.dietInt--; +} +protected void consumeRightParen() { + // PushRPAREN ::= ')' + pushOnIntStack(this.rParenPos); +} +// This method is part of an automatic generation : do NOT edit-modify +protected void consumeRule(int act) { + switch ( act ) { + case 26 : // System.out.println("Type ::= PrimitiveType"); //$NON-NLS-1$ + consumePrimitiveType(); + break ; + + case 40 : // System.out.println("ReferenceType ::= ClassOrInterfaceType"); //$NON-NLS-1$ + consumeReferenceType(); + break ; + + case 49 : // System.out.println("QualifiedName ::= Name DOT SimpleName"); //$NON-NLS-1$ + consumeQualifiedName(); + break ; + + case 50 : // System.out.println("CompilationUnit ::= EnterCompilationUnit PackageDeclarationopt..."); //$NON-NLS-1$ + consumeCompilationUnit(); + break ; + + case 51 : // System.out.println("EnterCompilationUnit ::="); //$NON-NLS-1$ + consumeEnterCompilationUnit(); + break ; + + case 64 : // System.out.println("CatchHeader ::= catch LPAREN FormalParameter RPAREN LBRACE"); //$NON-NLS-1$ + consumeCatchHeader(); + break ; + + case 66 : // System.out.println("ImportDeclarations ::= ImportDeclarations ImportDeclaration"); //$NON-NLS-1$ + consumeImportDeclarations(); + break ; + + case 68 : // System.out.println("TypeDeclarations ::= TypeDeclarations TypeDeclaration"); //$NON-NLS-1$ + consumeTypeDeclarations(); + break ; + + case 69 : // System.out.println("PackageDeclaration ::= PackageDeclarationName SEMICOLON"); //$NON-NLS-1$ + consumePackageDeclaration(); + break ; + + case 70 : // System.out.println("PackageDeclarationName ::= package Name"); //$NON-NLS-1$ + consumePackageDeclarationName(); + break ; + + case 73 : // System.out.println("SingleTypeImportDeclaration ::= SingleTypeImportDeclarationName..."); //$NON-NLS-1$ + consumeSingleTypeImportDeclaration(); + break ; + + case 74 : // System.out.println("SingleTypeImportDeclarationName ::= import Name"); //$NON-NLS-1$ + consumeSingleTypeImportDeclarationName(); + break ; + + case 75 : // System.out.println("TypeImportOnDemandDeclaration ::= TypeImportOnDemandDeclarationName"); //$NON-NLS-1$ + consumeTypeImportOnDemandDeclaration(); + break ; + + case 76 : // System.out.println("TypeImportOnDemandDeclarationName ::= import Name DOT MULTIPLY"); //$NON-NLS-1$ + consumeTypeImportOnDemandDeclarationName(); + break ; + + case 79 : // System.out.println("TypeDeclaration ::= SEMICOLON"); //$NON-NLS-1$ + consumeEmptyTypeDeclaration(); + break ; + + case 93 : // System.out.println("ClassDeclaration ::= ClassHeader ClassBody"); //$NON-NLS-1$ + consumeClassDeclaration(); + break ; + + case 94 : // System.out.println("ClassHeader ::= ClassHeaderName ClassHeaderExtendsopt..."); //$NON-NLS-1$ + consumeClassHeader(); + break ; + + case 95 : // System.out.println("ClassHeaderName ::= Modifiersopt class Identifier"); //$NON-NLS-1$ + consumeClassHeaderName(); + break ; + + case 96 : // System.out.println("ClassHeaderExtends ::= extends ClassType"); //$NON-NLS-1$ + consumeClassHeaderExtends(); + break ; + + case 97 : // System.out.println("ClassHeaderImplements ::= implements InterfaceTypeList"); //$NON-NLS-1$ + consumeClassHeaderImplements(); + break ; + + case 99 : // System.out.println("InterfaceTypeList ::= InterfaceTypeList COMMA InterfaceType"); //$NON-NLS-1$ + consumeInterfaceTypeList(); + break ; + + case 100 : // System.out.println("InterfaceType ::= ClassOrInterfaceType"); //$NON-NLS-1$ + consumeInterfaceType(); + break ; + + case 103 : // System.out.println("ClassBodyDeclarations ::= ClassBodyDeclarations ClassBodyDeclaration"); //$NON-NLS-1$ + consumeClassBodyDeclarations(); + break ; + + case 107 : // System.out.println("ClassBodyDeclaration ::= Diet NestedMethod Block"); //$NON-NLS-1$ + consumeClassBodyDeclaration(); + break ; + + case 108 : // System.out.println("Diet ::="); //$NON-NLS-1$ + consumeDiet(); + break ; + + case 109 : // System.out.println("Initializer ::= Diet NestedMethod Block"); //$NON-NLS-1$ + consumeClassBodyDeclaration(); + break ; + + case 116 : // System.out.println("ClassMemberDeclaration ::= SEMICOLON"); //$NON-NLS-1$ + consumeEmptyClassMemberDeclaration(); + break ; + + case 117 : // System.out.println("FieldDeclaration ::= Modifiersopt Type VariableDeclarators SEMICOLON"); //$NON-NLS-1$ + consumeFieldDeclaration(); + break ; + + case 119 : // System.out.println("VariableDeclarators ::= VariableDeclarators COMMA VariableDeclarator"); //$NON-NLS-1$ + consumeVariableDeclarators(); + break ; + + case 122 : // System.out.println("EnterVariable ::="); //$NON-NLS-1$ + consumeEnterVariable(); + break ; + + case 123 : // System.out.println("ExitVariableWithInitialization ::="); //$NON-NLS-1$ + consumeExitVariableWithInitialization(); + break ; + + case 124 : // System.out.println("ExitVariableWithoutInitialization ::="); //$NON-NLS-1$ + consumeExitVariableWithoutInitialization(); + break ; + + case 125 : // System.out.println("ForceNoDiet ::="); //$NON-NLS-1$ + consumeForceNoDiet(); + break ; + + case 126 : // System.out.println("RestoreDiet ::="); //$NON-NLS-1$ + consumeRestoreDiet(); + break ; + + case 131 : // System.out.println("MethodDeclaration ::= MethodHeader MethodBody"); //$NON-NLS-1$ + // set to true to consume a method with a body + consumeMethodDeclaration(true); + break ; + + case 132 : // System.out.println("AbstractMethodDeclaration ::= MethodHeader SEMICOLON"); //$NON-NLS-1$ + // set to false to consume a method without body + consumeMethodDeclaration(false); + break ; + + case 133 : // System.out.println("MethodHeader ::= MethodHeaderName MethodHeaderParameters..."); //$NON-NLS-1$ + consumeMethodHeader(); + break ; + + case 134 : // System.out.println("MethodHeaderName ::= Modifiersopt Type Identifier LPAREN"); //$NON-NLS-1$ + consumeMethodHeaderName(); + break ; + + case 135 : // System.out.println("MethodHeaderParameters ::= FormalParameterListopt RPAREN"); //$NON-NLS-1$ + consumeMethodHeaderParameters(); + break ; + + case 136 : // System.out.println("MethodHeaderExtendedDims ::= Dimsopt"); //$NON-NLS-1$ + consumeMethodHeaderExtendedDims(); + break ; + + case 137 : // System.out.println("MethodHeaderThrowsClause ::= throws ClassTypeList"); //$NON-NLS-1$ + consumeMethodHeaderThrowsClause(); + break ; + + case 138 : // System.out.println("ConstructorHeader ::= ConstructorHeaderName MethodHeaderParameters"); //$NON-NLS-1$ + consumeConstructorHeader(); + break ; + + case 139 : // System.out.println("ConstructorHeaderName ::= Modifiersopt Identifier LPAREN"); //$NON-NLS-1$ + consumeConstructorHeaderName(); + break ; + + case 141 : // System.out.println("FormalParameterList ::= FormalParameterList COMMA FormalParameter"); //$NON-NLS-1$ + consumeFormalParameterList(); + break ; + + case 142 : // System.out.println("FormalParameter ::= Modifiersopt Type VariableDeclaratorId"); //$NON-NLS-1$ + // the boolean is used to know if the modifiers should be reset + consumeFormalParameter(); + break ; + + case 144 : // System.out.println("ClassTypeList ::= ClassTypeList COMMA ClassTypeElt"); //$NON-NLS-1$ + consumeClassTypeList(); + break ; + + case 145 : // System.out.println("ClassTypeElt ::= ClassType"); //$NON-NLS-1$ + consumeClassTypeElt(); + break ; + + case 146 : // System.out.println("MethodBody ::= NestedMethod LBRACE BlockStatementsopt RBRACE"); //$NON-NLS-1$ + consumeMethodBody(); + break ; + + case 147 : // System.out.println("NestedMethod ::="); //$NON-NLS-1$ + consumeNestedMethod(); + break ; + + case 148 : // System.out.println("StaticInitializer ::= StaticOnly Block"); //$NON-NLS-1$ + consumeStaticInitializer(); + break ; + + case 149 : // System.out.println("StaticOnly ::= static"); //$NON-NLS-1$ + consumeStaticOnly(); + break ; + + case 150 : // System.out.println("ConstructorDeclaration ::= ConstructorHeader MethodBody"); //$NON-NLS-1$ + consumeConstructorDeclaration() ; + break ; + + case 151 : // System.out.println("ConstructorDeclaration ::= ConstructorHeader SEMICOLON"); //$NON-NLS-1$ + consumeInvalidConstructorDeclaration() ; + break ; + + case 152 : // System.out.println("ExplicitConstructorInvocation ::= this LPAREN ArgumentListopt RPAREN"); //$NON-NLS-1$ + consumeExplicitConstructorInvocation(0,ExplicitConstructorCall.This); + break ; + + case 153 : // System.out.println("ExplicitConstructorInvocation ::= super LPAREN ArgumentListopt..."); //$NON-NLS-1$ + consumeExplicitConstructorInvocation(0,ExplicitConstructorCall.Super); + break ; + + case 154 : // System.out.println("ExplicitConstructorInvocation ::= Primary DOT super LPAREN..."); //$NON-NLS-1$ + consumeExplicitConstructorInvocation(1, ExplicitConstructorCall.Super); + break ; + + case 155 : // System.out.println("ExplicitConstructorInvocation ::= Name DOT super LPAREN..."); //$NON-NLS-1$ + consumeExplicitConstructorInvocation(2, ExplicitConstructorCall.Super); + break ; + + case 156 : // System.out.println("ExplicitConstructorInvocation ::= Primary DOT this LPAREN..."); //$NON-NLS-1$ + consumeExplicitConstructorInvocation(1, ExplicitConstructorCall.This); + break ; + + case 157 : // System.out.println("ExplicitConstructorInvocation ::= Name DOT this LPAREN..."); //$NON-NLS-1$ + consumeExplicitConstructorInvocation(2, ExplicitConstructorCall.This); + break ; + + case 158 : // System.out.println("InterfaceDeclaration ::= InterfaceHeader InterfaceBody"); //$NON-NLS-1$ + consumeInterfaceDeclaration(); + break ; + + case 159 : // System.out.println("InterfaceHeader ::= InterfaceHeaderName InterfaceHeaderExtendsopt"); //$NON-NLS-1$ + consumeInterfaceHeader(); + break ; + + case 160 : // System.out.println("InterfaceHeaderName ::= Modifiersopt interface Identifier"); //$NON-NLS-1$ + consumeInterfaceHeaderName(); + break ; + + case 162 : // System.out.println("InterfaceHeaderExtends ::= extends InterfaceTypeList"); //$NON-NLS-1$ + consumeInterfaceHeaderExtends(); + break ; + + case 165 : // System.out.println("InterfaceMemberDeclarations ::= InterfaceMemberDeclarations..."); //$NON-NLS-1$ + consumeInterfaceMemberDeclarations(); + break ; + + case 166 : // System.out.println("InterfaceMemberDeclaration ::= SEMICOLON"); //$NON-NLS-1$ + consumeEmptyInterfaceMemberDeclaration(); + break ; + + case 169 : // System.out.println("InterfaceMemberDeclaration ::= InvalidMethodDeclaration"); //$NON-NLS-1$ + ignoreMethodBody(); + break ; + + case 170 : // System.out.println("InvalidConstructorDeclaration ::= ConstructorHeader MethodBody"); //$NON-NLS-1$ + ignoreInvalidConstructorDeclaration(true); + break ; + + case 171 : // System.out.println("InvalidConstructorDeclaration ::= ConstructorHeader SEMICOLON"); //$NON-NLS-1$ + ignoreInvalidConstructorDeclaration(false); + break ; + + case 177 : // System.out.println("ArrayInitializer ::= LBRACE ,opt RBRACE"); //$NON-NLS-1$ + consumeEmptyArrayInitializer(); + break ; + + case 178 : // System.out.println("ArrayInitializer ::= LBRACE VariableInitializers RBRACE"); //$NON-NLS-1$ + consumeArrayInitializer(); + break ; + + case 179 : // System.out.println("ArrayInitializer ::= LBRACE VariableInitializers COMMA RBRACE"); //$NON-NLS-1$ + consumeArrayInitializer(); + break ; + + case 181 : // System.out.println("VariableInitializers ::= VariableInitializers COMMA..."); //$NON-NLS-1$ + consumeVariableInitializers(); + break ; + + case 182 : // System.out.println("Block ::= OpenBlock LBRACE BlockStatementsopt RBRACE"); //$NON-NLS-1$ + consumeBlock(); + break ; + + case 183 : // System.out.println("OpenBlock ::="); //$NON-NLS-1$ + consumeOpenBlock() ; + break ; + + case 185 : // System.out.println("BlockStatements ::= BlockStatements BlockStatement"); //$NON-NLS-1$ + consumeBlockStatements() ; + break ; + + case 189 : // System.out.println("BlockStatement ::= InvalidInterfaceDeclaration"); //$NON-NLS-1$ + ignoreInterfaceDeclaration(); + break ; + + case 190 : // System.out.println("LocalVariableDeclarationStatement ::= LocalVariableDeclaration..."); //$NON-NLS-1$ + consumeLocalVariableDeclarationStatement(); + break ; + + case 191 : // System.out.println("LocalVariableDeclaration ::= Type PushModifiers VariableDeclarators"); //$NON-NLS-1$ + consumeLocalVariableDeclaration(); + break ; + + case 192 : // System.out.println("LocalVariableDeclaration ::= Modifiers Type PushModifiers..."); //$NON-NLS-1$ + consumeLocalVariableDeclaration(); + break ; + + case 193 : // System.out.println("PushModifiers ::="); //$NON-NLS-1$ + consumePushModifiers(); + break ; + + case 217 : // System.out.println("EmptyStatement ::= SEMICOLON"); //$NON-NLS-1$ + consumeEmptyStatement(); + break ; + + case 218 : // System.out.println("LabeledStatement ::= Identifier COLON Statement"); //$NON-NLS-1$ + consumeStatementLabel() ; + break ; + + case 219 : // System.out.println("LabeledStatementNoShortIf ::= Identifier COLON StatementNoShortIf"); //$NON-NLS-1$ + consumeStatementLabel() ; + break ; + + case 220 : // System.out.println("ExpressionStatement ::= StatementExpression SEMICOLON"); //$NON-NLS-1$ + consumeExpressionStatement(); + break ; + + case 229 : // System.out.println("IfThenStatement ::= if LPAREN Expression RPAREN Statement"); //$NON-NLS-1$ + consumeStatementIfNoElse(); + break ; + + case 230 : // System.out.println("IfThenElseStatement ::= if LPAREN Expression RPAREN..."); //$NON-NLS-1$ + consumeStatementIfWithElse(); + break ; + + case 231 : // System.out.println("IfThenElseStatementNoShortIf ::= if LPAREN Expression RPAREN..."); //$NON-NLS-1$ + consumeStatementIfWithElse(); + break ; + + case 232 : // System.out.println("SwitchStatement ::= switch LPAREN Expression RPAREN OpenBlock..."); //$NON-NLS-1$ + consumeStatementSwitch() ; + break ; + + case 233 : // System.out.println("SwitchBlock ::= LBRACE RBRACE"); //$NON-NLS-1$ + consumeEmptySwitchBlock() ; + break ; + + case 236 : // System.out.println("SwitchBlock ::= LBRACE SwitchBlockStatements SwitchLabels RBRACE"); //$NON-NLS-1$ + consumeSwitchBlock() ; + break ; + + case 238 : // System.out.println("SwitchBlockStatements ::= SwitchBlockStatements SwitchBlockStatement"); //$NON-NLS-1$ + consumeSwitchBlockStatements() ; + break ; + + case 239 : // System.out.println("SwitchBlockStatement ::= SwitchLabels BlockStatements"); //$NON-NLS-1$ + consumeSwitchBlockStatement() ; + break ; + + case 241 : // System.out.println("SwitchLabels ::= SwitchLabels SwitchLabel"); //$NON-NLS-1$ + consumeSwitchLabels() ; + break ; + + case 242 : // System.out.println("SwitchLabel ::= case ConstantExpression COLON"); //$NON-NLS-1$ + consumeCaseLabel(); + break ; + + case 243 : // System.out.println("SwitchLabel ::= default COLON"); //$NON-NLS-1$ + consumeDefaultLabel(); + break ; + + case 244 : // System.out.println("WhileStatement ::= while LPAREN Expression RPAREN Statement"); //$NON-NLS-1$ + consumeStatementWhile() ; + break ; + + case 245 : // System.out.println("WhileStatementNoShortIf ::= while LPAREN Expression RPAREN..."); //$NON-NLS-1$ + consumeStatementWhile() ; + break ; + + case 246 : // System.out.println("DoStatement ::= do Statement while LPAREN Expression RPAREN..."); //$NON-NLS-1$ + consumeStatementDo() ; + break ; + + case 247 : // System.out.println("ForStatement ::= for LPAREN ForInitopt SEMICOLON Expressionopt..."); //$NON-NLS-1$ + consumeStatementFor() ; + break ; + + case 248 : // System.out.println("ForStatementNoShortIf ::= for LPAREN ForInitopt SEMICOLON..."); //$NON-NLS-1$ + consumeStatementFor() ; + break ; + + case 249 : // System.out.println("ForInit ::= StatementExpressionList"); //$NON-NLS-1$ + consumeForInit() ; + break ; + + case 253 : // System.out.println("StatementExpressionList ::= StatementExpressionList COMMA..."); //$NON-NLS-1$ + consumeStatementExpressionList() ; + break ; + + case 254 : // System.out.println("AssertStatement ::= assert Expression SEMICOLON"); //$NON-NLS-1$ + consumeSimpleAssertStatement() ; + break ; + + case 255 : // System.out.println("AssertStatement ::= assert Expression COLON Expression SEMICOLON"); //$NON-NLS-1$ + consumeAssertStatement() ; + break ; + + case 256 : // System.out.println("BreakStatement ::= break SEMICOLON"); //$NON-NLS-1$ + consumeStatementBreak() ; + break ; + + case 257 : // System.out.println("BreakStatement ::= break Identifier SEMICOLON"); //$NON-NLS-1$ + consumeStatementBreakWithLabel() ; + break ; + + case 258 : // System.out.println("ContinueStatement ::= continue SEMICOLON"); //$NON-NLS-1$ + consumeStatementContinue() ; + break ; + + case 259 : // System.out.println("ContinueStatement ::= continue Identifier SEMICOLON"); //$NON-NLS-1$ + consumeStatementContinueWithLabel() ; + break ; + + case 260 : // System.out.println("ReturnStatement ::= return Expressionopt SEMICOLON"); //$NON-NLS-1$ + consumeStatementReturn() ; + break ; + + case 261 : // System.out.println("ThrowStatement ::= throw Expression SEMICOLON"); //$NON-NLS-1$ + consumeStatementThrow(); + + break ; + + case 262 : // System.out.println("SynchronizedStatement ::= OnlySynchronized LPAREN Expression RPAREN"); //$NON-NLS-1$ + consumeStatementSynchronized(); + break ; + + case 263 : // System.out.println("OnlySynchronized ::= synchronized"); //$NON-NLS-1$ + consumeOnlySynchronized(); + break ; + + case 264 : // System.out.println("TryStatement ::= try TryBlock Catches"); //$NON-NLS-1$ + consumeStatementTry(false); + break ; + + case 265 : // System.out.println("TryStatement ::= try TryBlock Catchesopt Finally"); //$NON-NLS-1$ + consumeStatementTry(true); + break ; + + case 267 : // System.out.println("ExitTryBlock ::="); //$NON-NLS-1$ + consumeExitTryBlock(); + break ; + + case 269 : // System.out.println("Catches ::= Catches CatchClause"); //$NON-NLS-1$ + consumeCatches(); + break ; + + case 270 : // System.out.println("CatchClause ::= catch LPAREN FormalParameter RPAREN Block"); //$NON-NLS-1$ + consumeStatementCatch() ; + break ; + + case 272 : // System.out.println("PushLPAREN ::= LPAREN"); //$NON-NLS-1$ + consumeLeftParen(); + break ; + + case 273 : // System.out.println("PushRPAREN ::= RPAREN"); //$NON-NLS-1$ + consumeRightParen(); + break ; + + case 278 : // System.out.println("PrimaryNoNewArray ::= this"); //$NON-NLS-1$ + consumePrimaryNoNewArrayThis(); + break ; + + case 279 : // System.out.println("PrimaryNoNewArray ::= PushLPAREN Expression PushRPAREN"); //$NON-NLS-1$ + consumePrimaryNoNewArray(); + break ; + + case 282 : // System.out.println("PrimaryNoNewArray ::= Name DOT this"); //$NON-NLS-1$ + consumePrimaryNoNewArrayNameThis(); + break ; + + case 283 : // System.out.println("PrimaryNoNewArray ::= Name DOT super"); //$NON-NLS-1$ + consumePrimaryNoNewArrayNameSuper(); + break ; + + case 284 : // System.out.println("PrimaryNoNewArray ::= Name DOT class"); //$NON-NLS-1$ + consumePrimaryNoNewArrayName(); + break ; + + case 285 : // System.out.println("PrimaryNoNewArray ::= ArrayType DOT class"); //$NON-NLS-1$ + consumePrimaryNoNewArrayArrayType(); + break ; + + case 286 : // System.out.println("PrimaryNoNewArray ::= PrimitiveType DOT class"); //$NON-NLS-1$ + consumePrimaryNoNewArrayPrimitiveType(); + break ; + + case 289 : // System.out.println("AllocationHeader ::= new ClassType LPAREN ArgumentListopt RPAREN"); //$NON-NLS-1$ + consumeAllocationHeader(); + break ; + + case 290 : // System.out.println("ClassInstanceCreationExpression ::= new ClassType LPAREN..."); //$NON-NLS-1$ + consumeClassInstanceCreationExpression(); + break ; + + case 291 : // System.out.println("ClassInstanceCreationExpression ::= Primary DOT new SimpleName..."); //$NON-NLS-1$ + consumeClassInstanceCreationExpressionQualified() ; + break ; + + case 292 : // System.out.println("ClassInstanceCreationExpression ::=..."); //$NON-NLS-1$ + consumeClassInstanceCreationExpressionQualified() ; + break ; + + case 293 : // System.out.println("ClassInstanceCreationExpressionName ::= Name DOT"); //$NON-NLS-1$ + consumeClassInstanceCreationExpressionName() ; + break ; + + case 294 : // System.out.println("ClassBodyopt ::="); //$NON-NLS-1$ + consumeClassBodyopt(); + break ; + + case 296 : // System.out.println("EnterAnonymousClassBody ::="); //$NON-NLS-1$ + consumeEnterAnonymousClassBody(); + break ; + + case 298 : // System.out.println("ArgumentList ::= ArgumentList COMMA Expression"); //$NON-NLS-1$ + consumeArgumentList(); + break ; + + case 299 : // System.out.println("ArrayCreationHeader ::= new PrimitiveType DimWithOrWithOutExprs"); //$NON-NLS-1$ + consumeArrayCreationHeader(); + break ; + + case 300 : // System.out.println("ArrayCreationHeader ::= new ClassOrInterfaceType..."); //$NON-NLS-1$ + consumeArrayCreationHeader(); + break ; + + case 301 : // System.out.println("ArrayCreationWithoutArrayInitializer ::= new PrimitiveType..."); //$NON-NLS-1$ + consumeArrayCreationExpressionWithoutInitializer(); + break ; + + case 302 : // System.out.println("ArrayCreationWithArrayInitializer ::= new PrimitiveType..."); //$NON-NLS-1$ + consumeArrayCreationExpressionWithInitializer(); + break ; + + case 303 : // System.out.println("ArrayCreationWithoutArrayInitializer ::= new ClassOrInterfaceType..."); //$NON-NLS-1$ + consumeArrayCreationExpressionWithoutInitializer(); + break ; + + case 304 : // System.out.println("ArrayCreationWithArrayInitializer ::= new ClassOrInterfaceType..."); //$NON-NLS-1$ + consumeArrayCreationExpressionWithInitializer(); + break ; + + case 306 : // System.out.println("DimWithOrWithOutExprs ::= DimWithOrWithOutExprs DimWithOrWithOutExpr"); //$NON-NLS-1$ + consumeDimWithOrWithOutExprs(); + break ; + + case 308 : // System.out.println("DimWithOrWithOutExpr ::= LBRACKET RBRACKET"); //$NON-NLS-1$ + consumeDimWithOrWithOutExpr(); + break ; + + case 309 : // System.out.println("Dims ::= DimsLoop"); //$NON-NLS-1$ + consumeDims(); + break ; + + case 312 : // System.out.println("OneDimLoop ::= LBRACKET RBRACKET"); //$NON-NLS-1$ + consumeOneDimLoop(); + break ; + + case 313 : // System.out.println("FieldAccess ::= Primary DOT Identifier"); //$NON-NLS-1$ + consumeFieldAccess(false); + break ; + + case 314 : // System.out.println("FieldAccess ::= super DOT Identifier"); //$NON-NLS-1$ + consumeFieldAccess(true); + break ; + + case 315 : // System.out.println("MethodInvocation ::= Name LPAREN ArgumentListopt RPAREN"); //$NON-NLS-1$ + consumeMethodInvocationName(); + break ; + + case 316 : // System.out.println("MethodInvocation ::= Primary DOT Identifier LPAREN ArgumentListopt"); //$NON-NLS-1$ + consumeMethodInvocationPrimary(); + break ; + + case 317 : // System.out.println("MethodInvocation ::= super DOT Identifier LPAREN ArgumentListopt..."); //$NON-NLS-1$ + consumeMethodInvocationSuper(); + break ; + + case 318 : // System.out.println("ArrayAccess ::= Name LBRACKET Expression RBRACKET"); //$NON-NLS-1$ + consumeArrayAccess(true); + break ; + + case 319 : // System.out.println("ArrayAccess ::= PrimaryNoNewArray LBRACKET Expression RBRACKET"); //$NON-NLS-1$ + consumeArrayAccess(false); + break ; + + case 320 : // System.out.println("ArrayAccess ::= ArrayCreationWithArrayInitializer LBRACKET..."); //$NON-NLS-1$ + consumeArrayAccess(false); + break ; + + case 322 : // System.out.println("PostfixExpression ::= Name"); //$NON-NLS-1$ + consumePostfixExpression(); + break ; + + case 325 : // System.out.println("PostIncrementExpression ::= PostfixExpression PLUS_PLUS"); //$NON-NLS-1$ + consumeUnaryExpression(OperatorIds.PLUS,true); + break ; + + case 326 : // System.out.println("PostDecrementExpression ::= PostfixExpression MINUS_MINUS"); //$NON-NLS-1$ + consumeUnaryExpression(OperatorIds.MINUS,true); + break ; + + case 327 : // System.out.println("PushPosition ::="); //$NON-NLS-1$ + consumePushPosition(); + break ; + + case 330 : // System.out.println("UnaryExpression ::= PLUS PushPosition UnaryExpression"); //$NON-NLS-1$ + consumeUnaryExpression(OperatorIds.PLUS); + break ; + + case 331 : // System.out.println("UnaryExpression ::= MINUS PushPosition UnaryExpression"); //$NON-NLS-1$ + consumeUnaryExpression(OperatorIds.MINUS); + break ; + + case 333 : // System.out.println("PreIncrementExpression ::= PLUS_PLUS PushPosition UnaryExpression"); //$NON-NLS-1$ + consumeUnaryExpression(OperatorIds.PLUS,false); + break ; + + case 334 : // System.out.println("PreDecrementExpression ::= MINUS_MINUS PushPosition UnaryExpression"); //$NON-NLS-1$ + consumeUnaryExpression(OperatorIds.MINUS,false); + break ; + + case 336 : // System.out.println("UnaryExpressionNotPlusMinus ::= TWIDDLE PushPosition UnaryExpression"); //$NON-NLS-1$ + consumeUnaryExpression(OperatorIds.TWIDDLE); + break ; + + case 337 : // System.out.println("UnaryExpressionNotPlusMinus ::= NOT PushPosition UnaryExpression"); //$NON-NLS-1$ + consumeUnaryExpression(OperatorIds.NOT); + break ; + + case 339 : // System.out.println("CastExpression ::= PushLPAREN PrimitiveType Dimsopt PushRPAREN..."); //$NON-NLS-1$ + consumeCastExpression(); + break ; + + case 340 : // System.out.println("CastExpression ::= PushLPAREN Name Dims PushRPAREN..."); //$NON-NLS-1$ + consumeCastExpression(); + break ; + + case 341 : // System.out.println("CastExpression ::= PushLPAREN Expression PushRPAREN..."); //$NON-NLS-1$ + consumeCastExpressionLL1(); + break ; + + case 342 : // System.out.println("InsideCastExpression ::="); //$NON-NLS-1$ + consumeInsideCastExpression(); + break ; + + case 343 : // System.out.println("InsideCastExpressionLL1 ::="); //$NON-NLS-1$ + consumeInsideCastExpressionLL1(); + break ; + + case 345 : // System.out.println("MultiplicativeExpression ::= MultiplicativeExpression MULTIPLY..."); //$NON-NLS-1$ + consumeBinaryExpression(OperatorIds.MULTIPLY); + break ; + + case 346 : // System.out.println("MultiplicativeExpression ::= MultiplicativeExpression DIVIDE..."); //$NON-NLS-1$ + consumeBinaryExpression(OperatorIds.DIVIDE); + break ; + + case 347 : // System.out.println("MultiplicativeExpression ::= MultiplicativeExpression REMAINDER..."); //$NON-NLS-1$ + consumeBinaryExpression(OperatorIds.REMAINDER); + break ; + + case 349 : // System.out.println("AdditiveExpression ::= AdditiveExpression PLUS..."); //$NON-NLS-1$ + consumeBinaryExpression(OperatorIds.PLUS); + break ; + + case 350 : // System.out.println("AdditiveExpression ::= AdditiveExpression MINUS..."); //$NON-NLS-1$ + consumeBinaryExpression(OperatorIds.MINUS); + break ; + + case 352 : // System.out.println("ShiftExpression ::= ShiftExpression LEFT_SHIFT AdditiveExpression"); //$NON-NLS-1$ + consumeBinaryExpression(OperatorIds.LEFT_SHIFT); + break ; + + case 353 : // System.out.println("ShiftExpression ::= ShiftExpression RIGHT_SHIFT AdditiveExpression"); //$NON-NLS-1$ + consumeBinaryExpression(OperatorIds.RIGHT_SHIFT); + break ; + + case 354 : // System.out.println("ShiftExpression ::= ShiftExpression UNSIGNED_RIGHT_SHIFT..."); //$NON-NLS-1$ + consumeBinaryExpression(OperatorIds.UNSIGNED_RIGHT_SHIFT); + break ; + + case 356 : // System.out.println("RelationalExpression ::= RelationalExpression LESS ShiftExpression"); //$NON-NLS-1$ + consumeBinaryExpression(OperatorIds.LESS); + break ; + + case 357 : // System.out.println("RelationalExpression ::= RelationalExpression GREATER..."); //$NON-NLS-1$ + consumeBinaryExpression(OperatorIds.GREATER); + break ; + + case 358 : // System.out.println("RelationalExpression ::= RelationalExpression LESS_EQUAL..."); //$NON-NLS-1$ + consumeBinaryExpression(OperatorIds.LESS_EQUAL); + break ; + + case 359 : // System.out.println("RelationalExpression ::= RelationalExpression GREATER_EQUAL..."); //$NON-NLS-1$ + consumeBinaryExpression(OperatorIds.GREATER_EQUAL); + break ; + + case 360 : // System.out.println("RelationalExpression ::= RelationalExpression instanceof..."); //$NON-NLS-1$ + consumeInstanceOfExpression(OperatorIds.INSTANCEOF); + break ; + + case 362 : // System.out.println("EqualityExpression ::= EqualityExpression EQUAL_EQUAL..."); //$NON-NLS-1$ + consumeEqualityExpression(OperatorIds.EQUAL_EQUAL); + break ; + + case 363 : // System.out.println("EqualityExpression ::= EqualityExpression NOT_EQUAL..."); //$NON-NLS-1$ + consumeEqualityExpression(OperatorIds.NOT_EQUAL); + break ; + + case 365 : // System.out.println("AndExpression ::= AndExpression AND EqualityExpression"); //$NON-NLS-1$ + consumeBinaryExpression(OperatorIds.AND); + break ; + + case 367 : // System.out.println("ExclusiveOrExpression ::= ExclusiveOrExpression XOR AndExpression"); //$NON-NLS-1$ + consumeBinaryExpression(OperatorIds.XOR); + break ; + + case 369 : // System.out.println("InclusiveOrExpression ::= InclusiveOrExpression OR..."); //$NON-NLS-1$ + consumeBinaryExpression(OperatorIds.OR); + break ; + + case 371 : // System.out.println("ConditionalAndExpression ::= ConditionalAndExpression AND_AND..."); //$NON-NLS-1$ + consumeBinaryExpression(OperatorIds.AND_AND); + break ; + + case 373 : // System.out.println("ConditionalOrExpression ::= ConditionalOrExpression OR_OR..."); //$NON-NLS-1$ + consumeBinaryExpression(OperatorIds.OR_OR); + break ; + + case 375 : // System.out.println("ConditionalExpression ::= ConditionalOrExpression QUESTION..."); //$NON-NLS-1$ + consumeConditionalExpression(OperatorIds.QUESTIONCOLON) ; + break ; + + case 378 : // System.out.println("Assignment ::= PostfixExpression AssignmentOperator..."); //$NON-NLS-1$ + consumeAssignment(); + break ; + + case 380 : // System.out.println("Assignment ::= InvalidArrayInitializerAssignement"); //$NON-NLS-1$ + ignoreExpressionAssignment(); + break ; + + case 381 : // System.out.println("AssignmentOperator ::= EQUAL"); //$NON-NLS-1$ + consumeAssignmentOperator(EQUAL); + break ; + + case 382 : // System.out.println("AssignmentOperator ::= MULTIPLY_EQUAL"); //$NON-NLS-1$ + consumeAssignmentOperator(MULTIPLY); + break ; + + case 383 : // System.out.println("AssignmentOperator ::= DIVIDE_EQUAL"); //$NON-NLS-1$ + consumeAssignmentOperator(DIVIDE); + break ; + + case 384 : // System.out.println("AssignmentOperator ::= REMAINDER_EQUAL"); //$NON-NLS-1$ + consumeAssignmentOperator(REMAINDER); + break ; + + case 385 : // System.out.println("AssignmentOperator ::= PLUS_EQUAL"); //$NON-NLS-1$ + consumeAssignmentOperator(PLUS); + break ; + + case 386 : // System.out.println("AssignmentOperator ::= MINUS_EQUAL"); //$NON-NLS-1$ + consumeAssignmentOperator(MINUS); + break ; + + case 387 : // System.out.println("AssignmentOperator ::= LEFT_SHIFT_EQUAL"); //$NON-NLS-1$ + consumeAssignmentOperator(LEFT_SHIFT); + break ; + + case 388 : // System.out.println("AssignmentOperator ::= RIGHT_SHIFT_EQUAL"); //$NON-NLS-1$ + consumeAssignmentOperator(RIGHT_SHIFT); + break ; + + case 389 : // System.out.println("AssignmentOperator ::= UNSIGNED_RIGHT_SHIFT_EQUAL"); //$NON-NLS-1$ + consumeAssignmentOperator(UNSIGNED_RIGHT_SHIFT); + break ; + + case 390 : // System.out.println("AssignmentOperator ::= AND_EQUAL"); //$NON-NLS-1$ + consumeAssignmentOperator(AND); + break ; + + case 391 : // System.out.println("AssignmentOperator ::= XOR_EQUAL"); //$NON-NLS-1$ + consumeAssignmentOperator(XOR); + break ; + + case 392 : // System.out.println("AssignmentOperator ::= OR_EQUAL"); //$NON-NLS-1$ + consumeAssignmentOperator(OR); + break ; + + case 399 : // System.out.println("Expressionopt ::="); //$NON-NLS-1$ + consumeEmptyExpression(); + break ; + + case 403 : // System.out.println("ImportDeclarationsopt ::="); //$NON-NLS-1$ + consumeEmptyImportDeclarationsopt(); + break ; + + case 404 : // System.out.println("ImportDeclarationsopt ::= ImportDeclarations"); //$NON-NLS-1$ + consumeImportDeclarationsopt(); + break ; + + case 405 : // System.out.println("TypeDeclarationsopt ::="); //$NON-NLS-1$ + consumeEmptyTypeDeclarationsopt(); + break ; + + case 406 : // System.out.println("TypeDeclarationsopt ::= TypeDeclarations"); //$NON-NLS-1$ + consumeTypeDeclarationsopt(); + break ; + + case 407 : // System.out.println("ClassBodyDeclarationsopt ::="); //$NON-NLS-1$ + consumeEmptyClassBodyDeclarationsopt(); + break ; + + case 408 : // System.out.println("ClassBodyDeclarationsopt ::= NestedType ClassBodyDeclarations"); //$NON-NLS-1$ + consumeClassBodyDeclarationsopt(); + break ; + + case 409 : // System.out.println("Modifiersopt ::="); //$NON-NLS-1$ + consumeDefaultModifiers(); + break ; + + case 410 : // System.out.println("Modifiersopt ::= Modifiers"); //$NON-NLS-1$ + consumeModifiers(); + break ; + + case 411 : // System.out.println("BlockStatementsopt ::="); //$NON-NLS-1$ + consumeEmptyBlockStatementsopt(); + break ; + + case 413 : // System.out.println("Dimsopt ::="); //$NON-NLS-1$ + consumeEmptyDimsopt(); + break ; + + case 415 : // System.out.println("ArgumentListopt ::="); //$NON-NLS-1$ + consumeEmptyArgumentListopt(); + break ; + + case 419 : // System.out.println("FormalParameterListopt ::="); //$NON-NLS-1$ + consumeFormalParameterListopt(); + break ; + + case 423 : // System.out.println("InterfaceMemberDeclarationsopt ::="); //$NON-NLS-1$ + consumeEmptyInterfaceMemberDeclarationsopt(); + break ; + + case 424 : // System.out.println("InterfaceMemberDeclarationsopt ::= NestedType..."); //$NON-NLS-1$ + consumeInterfaceMemberDeclarationsopt(); + break ; + + case 425 : // System.out.println("NestedType ::="); //$NON-NLS-1$ + consumeNestedType(); + break ; + + case 426 : // System.out.println("ForInitopt ::="); //$NON-NLS-1$ + consumeEmptyForInitopt(); + break ; + + case 428 : // System.out.println("ForUpdateopt ::="); //$NON-NLS-1$ + consumeEmptyForUpdateopt(); + break ; + + case 432 : // System.out.println("Catchesopt ::="); //$NON-NLS-1$ + consumeEmptyCatchesopt(); + break ; + + } +} +protected void consumeSimpleAssertStatement() { + // AssertStatement ::= 'assert' Expression ';' + this.expressionLengthPtr--; + pushOnAstStack(new AssertStatement(this.expressionStack[this.expressionPtr--], this.intStack[this.intPtr--])); +} + +protected void consumeSingleTypeImportDeclaration() { + // SingleTypeImportDeclaration ::= SingleTypeImportDeclarationName ';' + + ImportReference impt = (ImportReference) this.astStack[this.astPtr]; + // flush comments defined prior to import statements + impt.declarationEnd = this.endStatementPosition; + impt.declarationSourceEnd = + this.flushCommentsDefinedPriorTo(impt.declarationSourceEnd); + + // recovery + if (this.currentElement != null) { + this.lastCheckPoint = impt.declarationSourceEnd + 1; + this.currentElement = this.currentElement.add(impt, 0); + this.lastIgnoredToken = -1; + this.restartRecovery = true; + // used to avoid branching back into the regular automaton + } +} +protected void consumeSingleTypeImportDeclarationName() { + // SingleTypeImportDeclarationName ::= 'import' Name + /* push an ImportRef build from the last name + stored in the identifier stack. */ + + ImportReference impt; + int length; + char[][] tokens = new char[length = this.identifierLengthStack[this.identifierLengthPtr--]][]; + this.identifierPtr -= length; + long[] positions = new long[length]; + System.arraycopy(this.identifierStack, this.identifierPtr + 1, tokens, 0, length); + System.arraycopy(this.identifierPositionStack, this.identifierPtr + 1, positions, 0, length); + pushOnAstStack(impt = new ImportReference(tokens, positions, false, AccDefault)); + + if (this.currentToken == TokenNameSEMICOLON){ + impt.declarationSourceEnd = this.scanner.currentPosition - 1; + } else { + impt.declarationSourceEnd = impt.sourceEnd; + } + impt.declarationEnd = impt.declarationSourceEnd; + //endPosition is just before the ; + impt.declarationSourceStart = this.intStack[this.intPtr--]; + + // recovery + if (this.currentElement != null){ + this.lastCheckPoint = impt.declarationSourceEnd+1; + this.currentElement = this.currentElement.add(impt, 0); + this.lastIgnoredToken = -1; + this.restartRecovery = true; // used to avoid branching back into the regular automaton + } +} +protected void consumeStatementBreak() { + // BreakStatement ::= 'break' ';' + // break pushs a position on intStack in case there is no label + + pushOnAstStack(new BreakStatement(null, this.intStack[this.intPtr--], this.endPosition)); +} +protected void consumeStatementBreakWithLabel() { + // BreakStatement ::= 'break' Identifier ';' + // break pushs a position on intStack in case there is no label + + pushOnAstStack( + new BreakStatement( + this.identifierStack[this.identifierPtr--], + this.intStack[this.intPtr--], + this.endPosition)); + this.identifierLengthPtr--; +} +protected void consumeStatementCatch() { + // CatchClause ::= 'catch' '(' FormalParameter ')' Block + + //catch are stored directly into the Try + //has they always comes two by two.... + //we remove one entry from the astlengthPtr. + //The construction of the try statement must + //then fetch the catches using 2*i and 2*i + 1 + + this.astLengthPtr--; + this.listLength = 0; // reset formalParameter counter (incremented for catch variable) +} +protected void consumeStatementContinue() { + // ContinueStatement ::= 'continue' ';' + // continue pushs a position on intStack in case there is no label + + pushOnAstStack( + new ContinueStatement( + null, + this.intStack[this.intPtr--], + this.endPosition)); +} +protected void consumeStatementContinueWithLabel() { + // ContinueStatement ::= 'continue' Identifier ';' + // continue pushs a position on intStack in case there is no label + + pushOnAstStack( + new ContinueStatement( + this.identifierStack[this.identifierPtr--], + this.intStack[this.intPtr--], + this.endPosition)); + this.identifierLengthPtr--; +} +protected void consumeStatementDo() { + // DoStatement ::= 'do' Statement 'while' '(' Expression ')' ';' + + //the 'while' pushes a value on intStack that we need to remove + this.intPtr--; + + Statement statement = (Statement) this.astStack[this.astPtr]; + this.expressionLengthPtr--; + this.astStack[this.astPtr] = + new DoStatement( + this.expressionStack[this.expressionPtr--], + statement, + this.intStack[this.intPtr--], + this.endPosition); +} +protected void consumeStatementExpressionList() { + // StatementExpressionList ::= StatementExpressionList ',' StatementExpression + concatExpressionLists(); +} +protected void consumeStatementFor() { + // ForStatement ::= 'for' '(' ForInitopt ';' Expressionopt ';' ForUpdateopt ')' Statement + // ForStatementNoShortIf ::= 'for' '(' ForInitopt ';' Expressionopt ';' ForUpdateopt ')' StatementNoShortIf + + int length; + Expression cond = null; + Statement[] inits, updates; + boolean scope = true; + + //statements + this.astLengthPtr--; + Statement statement = (Statement) this.astStack[this.astPtr--]; + + //updates are on the expresion stack + if ((length = this.expressionLengthStack[this.expressionLengthPtr--]) == 0) { + updates = null; + } else { + this.expressionPtr -= length; + System.arraycopy( + this.expressionStack, + this.expressionPtr + 1, + updates = new Statement[length], + 0, + length); + } + + if (this.expressionLengthStack[this.expressionLengthPtr--] != 0) + cond = this.expressionStack[this.expressionPtr--]; + + //inits may be on two different stacks + if ((length = this.astLengthStack[this.astLengthPtr--]) == 0) { + inits = null; + scope = false; + } else { + if (length == -1) { //on expressionStack + scope = false; + length = this.expressionLengthStack[this.expressionLengthPtr--]; + this.expressionPtr -= length; + System.arraycopy( + this.expressionStack, + this.expressionPtr + 1, + inits = new Statement[length], + 0, + length); + } else { //on astStack + this.astPtr -= length; + System.arraycopy( + this.astStack, + this.astPtr + 1, + inits = new Statement[length], + 0, + length); + } + } + pushOnAstStack( + new ForStatement( + inits, + cond, + updates, + statement, + scope, + this.intStack[this.intPtr--], + this.endStatementPosition)); +} +protected void consumeStatementIfNoElse() { + // IfThenStatement ::= 'if' '(' Expression ')' Statement + + //optimize the push/pop + this.expressionLengthPtr--; + Statement thenStatement = (Statement) this.astStack[this.astPtr]; + this.astStack[this.astPtr] = + new IfStatement( + this.expressionStack[this.expressionPtr--], + thenStatement, + this.intStack[this.intPtr--], + this.endStatementPosition); +} +protected void consumeStatementIfWithElse() { + // IfThenElseStatement ::= 'if' '(' Expression ')' StatementNoShortIf 'else' Statement + // IfThenElseStatementNoShortIf ::= 'if' '(' Expression ')' StatementNoShortIf 'else' StatementNoShortIf + + this.expressionLengthPtr--; + + // optimized {..., Then, Else } ==> {..., If } + this.astLengthPtr--; + + //optimize the push/pop + this.astStack[--this.astPtr] = + new IfStatement( + this.expressionStack[this.expressionPtr--], + (Statement) this.astStack[this.astPtr], + (Statement) this.astStack[this.astPtr + 1], + this.intStack[this.intPtr--], + this.endStatementPosition); +} +protected void consumeStatementLabel() { + // LabeledStatement ::= 'Identifier' ':' Statement + // LabeledStatementNoShortIf ::= 'Identifier' ':' StatementNoShortIf + + //optimize push/pop + Statement stmt = (Statement) this.astStack[this.astPtr]; + this.astStack[this.astPtr] = + new LabeledStatement( + this.identifierStack[this.identifierPtr], + stmt, + (int) (this.identifierPositionStack[this.identifierPtr--] >>> 32), + this.endStatementPosition); + this.identifierLengthPtr--; +} +protected void consumeStatementReturn() { + // ReturnStatement ::= 'return' Expressionopt ';' + // return pushs a position on intStack in case there is no expression + + if (this.expressionLengthStack[this.expressionLengthPtr--] != 0) { + pushOnAstStack( + new ReturnStatement( + this.expressionStack[this.expressionPtr--], + this.intStack[this.intPtr--], + this.endPosition) + ); + } else { + pushOnAstStack(new ReturnStatement(null, this.intStack[this.intPtr--], this.endPosition)); + } +} +protected void consumeStatementSwitch() { + // SwitchStatement ::= 'switch' OpenBlock '(' Expression ')' SwitchBlock + + //OpenBlock just makes the semantic action blockStart() + //the block is inlined but a scope need to be created + //if some declaration occurs. + + int length; + SwitchStatement switchStatement = new SwitchStatement(); + this.expressionLengthPtr--; + switchStatement.expression = this.expressionStack[this.expressionPtr--]; + if ((length = this.astLengthStack[this.astLengthPtr--]) != 0) { + this.astPtr -= length; + System.arraycopy( + this.astStack, + this.astPtr + 1, + switchStatement.statements = new Statement[length], + 0, + length); + } + switchStatement.explicitDeclarations = this.realBlockStack[this.realBlockPtr--]; + pushOnAstStack(switchStatement); + switchStatement.blockStart = this.intStack[this.intPtr--]; + switchStatement.sourceStart = this.intStack[this.intPtr--]; + switchStatement.sourceEnd = this.endStatementPosition; + if (length == 0 && !containsComment(switchStatement.blockStart, switchStatement.sourceEnd)) { + switchStatement.bits |= ASTNode.UndocumentedEmptyBlockMASK; + } +} +protected void consumeStatementSynchronized() { + // SynchronizedStatement ::= OnlySynchronized '(' Expression ')' Block + //optimize the push/pop + + if (this.astLengthStack[this.astLengthPtr] == 0) { + this.astLengthStack[this.astLengthPtr] = 1; + this.expressionLengthPtr--; + this.astStack[++this.astPtr] = + new SynchronizedStatement( + this.expressionStack[this.expressionPtr--], + null, + this.intStack[this.intPtr--], + this.endStatementPosition); + } else { + this.expressionLengthPtr--; + this.astStack[this.astPtr] = + new SynchronizedStatement( + this.expressionStack[this.expressionPtr--], + (Block) this.astStack[this.astPtr], + this.intStack[this.intPtr--], + this.endStatementPosition); + } + resetModifiers(); +} +protected void consumeStatementThrow() { + // ThrowStatement ::= 'throw' Expression ';' + this.expressionLengthPtr--; + pushOnAstStack(new ThrowStatement(this.expressionStack[this.expressionPtr--], this.intStack[this.intPtr--])); +} +protected void consumeStatementTry(boolean withFinally) { + //TryStatement ::= 'try' Block Catches + //TryStatement ::= 'try' Block Catchesopt Finally + + int length; + TryStatement tryStmt = new TryStatement(); + //finally + if (withFinally) { + this.astLengthPtr--; + tryStmt.finallyBlock = (Block) this.astStack[this.astPtr--]; + } + //catches are handle by two [see statementCatch] + if ((length = this.astLengthStack[this.astLengthPtr--]) != 0) { + if (length == 1) { + tryStmt.catchBlocks = new Block[] {(Block) this.astStack[this.astPtr--]}; + tryStmt.catchArguments = new Argument[] {(Argument) this.astStack[this.astPtr--]}; + } else { + Block[] bks = (tryStmt.catchBlocks = new Block[length]); + Argument[] args = (tryStmt.catchArguments = new Argument[length]); + while (length-- > 0) { + bks[length] = (Block) this.astStack[this.astPtr--]; + args[length] = (Argument) this.astStack[this.astPtr--]; + } + } + } + //try + this.astLengthPtr--; + tryStmt.tryBlock = (Block) this.astStack[this.astPtr--]; + + //positions + tryStmt.sourceEnd = this.endStatementPosition; + tryStmt.sourceStart = this.intStack[this.intPtr--]; + pushOnAstStack(tryStmt); +} +protected void consumeStatementWhile() { + // WhileStatement ::= 'while' '(' Expression ')' Statement + // WhileStatementNoShortIf ::= 'while' '(' Expression ')' StatementNoShortIf + + this.expressionLengthPtr--; + Statement statement = (Statement) this.astStack[this.astPtr]; + this.astStack[this.astPtr] = + new WhileStatement( + this.expressionStack[this.expressionPtr--], + statement, + this.intStack[this.intPtr--], + this.endStatementPosition); +} +protected void consumeStaticInitializer() { + // StaticInitializer ::= StaticOnly Block + //push an Initializer + //optimize the push/pop + Block block = (Block) this.astStack[this.astPtr]; + if (this.diet) block.bits &= ~ASTNode.UndocumentedEmptyBlockMASK; // clear bit set since was diet + Initializer initializer = new Initializer(block, AccStatic); + this.astStack[this.astPtr] = initializer; + initializer.sourceEnd = this.endStatementPosition; + initializer.declarationSourceEnd = flushCommentsDefinedPriorTo(this.endStatementPosition); + this.nestedMethod[this.nestedType] --; + initializer.declarationSourceStart = this.intStack[this.intPtr--]; + initializer.bodyStart = this.intStack[this.intPtr--]; + initializer.bodyEnd = this.endPosition; + // doc comment + initializer.javadoc = this.javadoc; + this.javadoc = null; + + // recovery + if (this.currentElement != null){ + this.lastCheckPoint = initializer.declarationSourceEnd; + this.currentElement = this.currentElement.add(initializer, 0); + this.lastIgnoredToken = -1; + } +} +protected void consumeStaticOnly() { + // StaticOnly ::= 'static' + int savedModifiersSourceStart = this.modifiersSourceStart; + checkComment(); // might update declaration source start + if (this.modifiersSourceStart >= savedModifiersSourceStart) { + this.modifiersSourceStart = savedModifiersSourceStart; + } + pushOnIntStack(this.scanner.currentPosition); + pushOnIntStack( + this.modifiersSourceStart >= 0 ? this.modifiersSourceStart : this.scanner.startPosition); + jumpOverMethodBody(); + this.nestedMethod[this.nestedType]++; + resetModifiers(); + + // recovery + if (this.currentElement != null){ + this.recoveredStaticInitializerStart = this.intStack[this.intPtr]; // remember start position only for static initializers + } +} +protected void consumeSwitchBlock() { + // SwitchBlock ::= '{' SwitchBlockStatements SwitchLabels '}' + concatNodeLists(); +} +protected void consumeSwitchBlockStatement() { + // SwitchBlockStatement ::= SwitchLabels BlockStatements + concatNodeLists(); +} +protected void consumeSwitchBlockStatements() { + // SwitchBlockStatements ::= SwitchBlockStatements SwitchBlockStatement + concatNodeLists(); +} +protected void consumeSwitchLabels() { + // SwitchLabels ::= SwitchLabels SwitchLabel + optimizedConcatNodeLists(); +} +protected void consumeToken(int type) { + /* remember the last consumed value */ + /* try to minimize the number of build values */ + checkNonExternalizedStringLiteral(); +// // clear the commentPtr of the scanner in case we read something different from a modifier +// switch(type) { +// case TokenNameabstract : +// case TokenNamestrictfp : +// case TokenNamefinal : +// case TokenNamenative : +// case TokenNameprivate : +// case TokenNameprotected : +// case TokenNamepublic : +// case TokenNametransient : +// case TokenNamevolatile : +// case TokenNamestatic : +// case TokenNamesynchronized : +// break; +// default: +// this.scanner.commentPtr = -1; +// } + //System.out.println(this.scanner.toStringAction(type)); + switch (type) { + case TokenNameIdentifier : + pushIdentifier(); + if (this.scanner.useAssertAsAnIndentifier) { + long positions = this.identifierPositionStack[this.identifierPtr]; + problemReporter().useAssertAsAnIdentifier((int) (positions >>> 32), (int) positions); + } +// this.scanner.commentPtr = -1; + break; + case TokenNameinterface : + adjustInterfaceModifiers(); + //'class' is pushing two int (positions) on the stack ==> 'interface' needs to do it too.... + pushOnIntStack(this.scanner.currentPosition - 1); + pushOnIntStack(this.scanner.startPosition); +// this.scanner.commentPtr = -1; + break; + case TokenNameabstract : + checkAndSetModifiers(AccAbstract); + break; + case TokenNamestrictfp : + checkAndSetModifiers(AccStrictfp); + break; + case TokenNamefinal : + checkAndSetModifiers(AccFinal); + break; + case TokenNamenative : + checkAndSetModifiers(AccNative); + break; + case TokenNameprivate : + checkAndSetModifiers(AccPrivate); + break; + case TokenNameprotected : + checkAndSetModifiers(AccProtected); + break; + case TokenNamepublic : + checkAndSetModifiers(AccPublic); + break; + case TokenNametransient : + checkAndSetModifiers(AccTransient); + break; + case TokenNamevolatile : + checkAndSetModifiers(AccVolatile); + break; + case TokenNamestatic : + checkAndSetModifiers(AccStatic); + break; + case TokenNamesynchronized : + this.synchronizedBlockSourceStart = this.scanner.startPosition; + checkAndSetModifiers(AccSynchronized); + break; + //============================== + case TokenNamevoid : + pushIdentifier(-T_void); + pushOnIntStack(this.scanner.currentPosition - 1); + pushOnIntStack(this.scanner.startPosition); +// this.scanner.commentPtr = -1; + break; + //push a default dimension while void is not part of the primitive + //declaration baseType and so takes the place of a type without getting into + //regular type parsing that generates a dimension on intStack + case TokenNameboolean : + pushIdentifier(-T_boolean); + pushOnIntStack(this.scanner.currentPosition - 1); + pushOnIntStack(this.scanner.startPosition); +// this.scanner.commentPtr = -1; + break; + case TokenNamebyte : + pushIdentifier(-T_byte); + pushOnIntStack(this.scanner.currentPosition - 1); + pushOnIntStack(this.scanner.startPosition); +// this.scanner.commentPtr = -1; + break; + case TokenNamechar : + pushIdentifier(-T_char); + pushOnIntStack(this.scanner.currentPosition - 1); + pushOnIntStack(this.scanner.startPosition); +// this.scanner.commentPtr = -1; + break; + case TokenNamedouble : + pushIdentifier(-T_double); + pushOnIntStack(this.scanner.currentPosition - 1); + pushOnIntStack(this.scanner.startPosition); +// this.scanner.commentPtr = -1; + break; + case TokenNamefloat : + pushIdentifier(-T_float); + pushOnIntStack(this.scanner.currentPosition - 1); + pushOnIntStack(this.scanner.startPosition); +// this.scanner.commentPtr = -1; + break; + case TokenNameint : + pushIdentifier(-T_int); + pushOnIntStack(this.scanner.currentPosition - 1); + pushOnIntStack(this.scanner.startPosition); +// this.scanner.commentPtr = -1; + break; + case TokenNamelong : + pushIdentifier(-T_long); + pushOnIntStack(this.scanner.currentPosition - 1); + pushOnIntStack(this.scanner.startPosition); +// this.scanner.commentPtr = -1; + break; + case TokenNameshort : + pushIdentifier(-T_short); + pushOnIntStack(this.scanner.currentPosition - 1); + pushOnIntStack(this.scanner.startPosition); +// this.scanner.commentPtr = -1; + break; + //============================== + case TokenNameIntegerLiteral : + pushOnExpressionStack( + new IntLiteral( + this.scanner.getCurrentTokenSource(), + this.scanner.startPosition, + this.scanner.currentPosition - 1)); +// this.scanner.commentPtr = -1; + break; + case TokenNameLongLiteral : + pushOnExpressionStack( + new LongLiteral( + this.scanner.getCurrentTokenSource(), + this.scanner.startPosition, + this.scanner.currentPosition - 1)); +// this.scanner.commentPtr = -1; + break; + case TokenNameFloatingPointLiteral : + pushOnExpressionStack( + new FloatLiteral( + this.scanner.getCurrentTokenSource(), + this.scanner.startPosition, + this.scanner.currentPosition - 1)); +// this.scanner.commentPtr = -1; + break; + case TokenNameDoubleLiteral : + pushOnExpressionStack( + new DoubleLiteral( + this.scanner.getCurrentTokenSource(), + this.scanner.startPosition, + this.scanner.currentPosition - 1)); +// this.scanner.commentPtr = -1; + break; + case TokenNameCharacterLiteral : + pushOnExpressionStack( + new CharLiteral( + this.scanner.getCurrentTokenSource(), + this.scanner.startPosition, + this.scanner.currentPosition - 1)); +// this.scanner.commentPtr = -1; + break; + case TokenNameStringLiteral : + StringLiteral stringLiteral = new StringLiteral( + this.scanner.getCurrentTokenSourceString(), + this.scanner.startPosition, + this.scanner.currentPosition - 1); + pushOnExpressionStack(stringLiteral); +// this.scanner.commentPtr = -1; + break; + case TokenNamefalse : + pushOnExpressionStack( + new FalseLiteral(this.scanner.startPosition, this.scanner.currentPosition - 1)); +// this.scanner.commentPtr = -1; + break; + case TokenNametrue : + pushOnExpressionStack( + new TrueLiteral(this.scanner.startPosition, this.scanner.currentPosition - 1)); + break; + case TokenNamenull : + pushOnExpressionStack( + new NullLiteral(this.scanner.startPosition, this.scanner.currentPosition - 1)); + break; + //============================ + case TokenNamesuper : + case TokenNamethis : + this.endPosition = this.scanner.currentPosition - 1; + pushOnIntStack(this.scanner.startPosition); + break; + case TokenNameassert : + case TokenNameimport : + case TokenNamepackage : + case TokenNamethrow : + case TokenNamedo : + case TokenNameif : + case TokenNamefor : + case TokenNameswitch : + case TokenNametry : + case TokenNamewhile : + case TokenNamebreak : + case TokenNamecontinue : + case TokenNamereturn : + case TokenNamecase : + pushOnIntStack(this.scanner.startPosition); + break; + case TokenNamenew : + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=40954 + resetModifiers(); + pushOnIntStack(this.scanner.startPosition); + break; + case TokenNameclass : + pushOnIntStack(this.scanner.currentPosition - 1); + pushOnIntStack(this.scanner.startPosition); + break; + case TokenNamedefault : + pushOnIntStack(this.scanner.startPosition); + pushOnIntStack(this.scanner.currentPosition - 1); + break; + //let extra semantic action decide when to push + case TokenNameRBRACKET : + case TokenNamePLUS : + case TokenNameMINUS : + case TokenNameNOT : + case TokenNameTWIDDLE : + this.endPosition = this.scanner.startPosition; + break; + case TokenNamePLUS_PLUS : + case TokenNameMINUS_MINUS : + this.endPosition = this.scanner.startPosition; + this.endStatementPosition = this.scanner.currentPosition - 1; + break; + case TokenNameRBRACE: + case TokenNameSEMICOLON : + this.endStatementPosition = this.scanner.currentPosition - 1; + this.endPosition = this.scanner.startPosition - 1; + //the item is not part of the potential futur expression/statement + break; + // in order to handle ( expression) ////// (cast)expression///// foo(x) + case TokenNameRPAREN : + this.rParenPos = this.scanner.currentPosition - 1; // position of the end of right parenthesis (in case of unicode \u0029) lex00101 + break; + case TokenNameLPAREN : + this.lParenPos = this.scanner.startPosition; + break; + // case TokenNameQUESTION : + // case TokenNameCOMMA : + // case TokenNameCOLON : + // case TokenNameEQUAL : + // case TokenNameLBRACKET : + // case TokenNameDOT : + // case TokenNameERROR : + // case TokenNameEOF : + // case TokenNamecase : + // case TokenNamecatch : + // case TokenNameelse : + // case TokenNameextends : + // case TokenNamefinally : + // case TokenNameimplements : + // case TokenNamethrows : + // case TokenNameinstanceof : + // case TokenNameEQUAL_EQUAL : + // case TokenNameLESS_EQUAL : + // case TokenNameGREATER_EQUAL : + // case TokenNameNOT_EQUAL : + // case TokenNameLEFT_SHIFT : + // case TokenNameRIGHT_SHIFT : + // case TokenNameUNSIGNED_RIGHT_SHIFT : + // case TokenNamePLUS_EQUAL : + // case TokenNameMINUS_EQUAL : + // case TokenNameMULTIPLY_EQUAL : + // case TokenNameDIVIDE_EQUAL : + // case TokenNameAND_EQUAL : + // case TokenNameOR_EQUAL : + // case TokenNameXOR_EQUAL : + // case TokenNameREMAINDER_EQUAL : + // case TokenNameLEFT_SHIFT_EQUAL : + // case TokenNameRIGHT_SHIFT_EQUAL : + // case TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL : + // case TokenNameOR_OR : + // case TokenNameAND_AND : + // case TokenNameREMAINDER : + // case TokenNameXOR : + // case TokenNameAND : + // case TokenNameMULTIPLY : + // case TokenNameOR : + // case TokenNameDIVIDE : + // case TokenNameGREATER : + // case TokenNameLESS : + } +} +protected void consumeTypeDeclarations() { + // TypeDeclarations ::= TypeDeclarations TypeDeclaration + concatNodeLists(); +} +protected void consumeTypeDeclarationsopt() { + // TypeDeclarationsopt ::= TypeDeclarations + int length; + if ((length = this.astLengthStack[this.astLengthPtr--]) != 0) { + this.astPtr -= length; + System.arraycopy(this.astStack, this.astPtr + 1, this.compilationUnit.types = new TypeDeclaration[length], 0, length); + } +} +protected void consumeTypeImportOnDemandDeclaration() { + // TypeImportOnDemandDeclaration ::= TypeImportOnDemandDeclarationName ';' + + ImportReference impt = (ImportReference) this.astStack[this.astPtr]; + // flush comments defined prior to import statements + impt.declarationEnd = this.endStatementPosition; + impt.declarationSourceEnd = + this.flushCommentsDefinedPriorTo(impt.declarationSourceEnd); + + // recovery + if (this.currentElement != null) { + this.lastCheckPoint = impt.declarationSourceEnd + 1; + this.currentElement = this.currentElement.add(impt, 0); + this.restartRecovery = true; + this.lastIgnoredToken = -1; + // used to avoid branching back into the regular automaton + } +} +protected void consumeTypeImportOnDemandDeclarationName() { + // TypeImportOnDemandDeclarationName ::= 'import' Name '.' '*' + /* push an ImportRef build from the last name + stored in the identifier stack. */ + + ImportReference impt; + int length; + char[][] tokens = new char[length = this.identifierLengthStack[this.identifierLengthPtr--]][]; + this.identifierPtr -= length; + long[] positions = new long[length]; + System.arraycopy(this.identifierStack, this.identifierPtr + 1, tokens, 0, length); + System.arraycopy(this.identifierPositionStack, this.identifierPtr + 1, positions, 0, length); + pushOnAstStack(impt = new ImportReference(tokens, positions, true, AccDefault)); + + if (this.currentToken == TokenNameSEMICOLON){ + impt.declarationSourceEnd = this.scanner.currentPosition - 1; + } else { + impt.declarationSourceEnd = impt.sourceEnd; + } + impt.declarationEnd = impt.declarationSourceEnd; + //endPosition is just before the ; + impt.declarationSourceStart = this.intStack[this.intPtr--]; + + // recovery + if (this.currentElement != null){ + this.lastCheckPoint = impt.declarationSourceEnd+1; + this.currentElement = this.currentElement.add(impt, 0); + this.lastIgnoredToken = -1; + this.restartRecovery = true; // used to avoid branching back into the regular automaton + } +} +protected void consumeUnaryExpression(int op) { + // UnaryExpression ::= '+' PushPosition UnaryExpression + // UnaryExpression ::= '-' PushPosition UnaryExpression + // UnaryExpressionNotPlusMinus ::= '~' PushPosition UnaryExpression + // UnaryExpressionNotPlusMinus ::= '!' PushPosition UnaryExpression + + //optimize the push/pop + + //handle manually the -2147483648 while it is not a real + //computation of an - and 2147483648 (notice that 2147483648 + //is Integer.MAX_VALUE+1.....) + //Same for -9223372036854775808L ............ + + //intStack have the position of the operator + + Expression r, exp = this.expressionStack[this.expressionPtr]; + if (op == MINUS) { + if ((exp instanceof IntLiteral) && (((IntLiteral) exp).mayRepresentMIN_VALUE())) { + r = this.expressionStack[this.expressionPtr] = new IntLiteralMinValue(); + } else { + if ((exp instanceof LongLiteral) && (((LongLiteral) exp).mayRepresentMIN_VALUE())) { + r = this.expressionStack[this.expressionPtr] = new LongLiteralMinValue(); + } else { + r = this.expressionStack[this.expressionPtr] = new UnaryExpression(exp, op); + } + } + } else { + r = this.expressionStack[this.expressionPtr] = new UnaryExpression(exp, op); + } + r.sourceStart = this.intStack[this.intPtr--]; + r.sourceEnd = exp.sourceEnd; +} +protected void consumeUnaryExpression(int op, boolean post) { + // PreIncrementExpression ::= '++' PushPosition UnaryExpression + // PreDecrementExpression ::= '--' PushPosition UnaryExpression + + // ++ and -- operators + //optimize the push/pop + + //intStack has the position of the operator when prefix + + Expression leftHandSide = this.expressionStack[this.expressionPtr]; + if (leftHandSide instanceof Reference) { + // ++foo()++ is unvalid + if (post) { + this.expressionStack[this.expressionPtr] = + new PostfixExpression( + leftHandSide, + IntLiteral.One, + op, + this.endStatementPosition); + } else { + this.expressionStack[this.expressionPtr] = + new PrefixExpression( + leftHandSide, + IntLiteral.One, + op, + this.intStack[this.intPtr--]); + } + } else { + //the ++ or the -- is NOT taken into account if code gen proceeds + if (!post) { + this.intPtr--; + } + problemReporter().invalidUnaryExpression(leftHandSide); + } +} +protected void consumeVariableDeclarators() { + // VariableDeclarators ::= VariableDeclarators ',' VariableDeclarator + optimizedConcatNodeLists(); +} +protected void consumeVariableInitializers() { + // VariableInitializers ::= VariableInitializers ',' VariableInitializer + concatExpressionLists(); +} +/** + * Given the current comment stack, answer whether some comment is available in a certain exclusive range + * + * @param sourceStart int + * @param sourceEnd int + * @return boolean + */ +public boolean containsComment(int sourceStart, int sourceEnd) { + int iComment = this.scanner.commentPtr; + for (; iComment >= 0; iComment--) { + int commentStart = this.scanner.commentStarts[iComment]; + // ignore comments before start + if (commentStart < sourceStart) continue; + // ignore comments after end + if (commentStart > sourceEnd) continue; + return true; + } + return false; +} +public MethodDeclaration convertToMethodDeclaration(ConstructorDeclaration c, CompilationResult compilationResult) { + MethodDeclaration m = new MethodDeclaration(compilationResult); + m.sourceStart = c.sourceStart; + m.sourceEnd = c.sourceEnd; + m.bodyStart = c.bodyStart; + m.bodyEnd = c.bodyEnd; + m.declarationSourceEnd = c.declarationSourceEnd; + m.declarationSourceStart = c.declarationSourceStart; + m.selector = c.selector; + m.statements = c.statements; + m.modifiers = c.modifiers; + m.arguments = c.arguments; + m.thrownExceptions = c.thrownExceptions; + m.explicitDeclarations = c.explicitDeclarations; + m.returnType = null; + return m; +} +protected TypeReference copyDims(TypeReference typeRef, int dim) { + return typeRef.copyDims(dim); +} +protected FieldDeclaration createFieldDeclaration(char[] fieldDeclarationName, int sourceStart, int sourceEnd) { + return new FieldDeclaration(fieldDeclarationName, sourceStart, sourceEnd); +} + +protected LocalDeclaration createLocalDeclaration(char[] localDeclarationName, int sourceStart, int sourceEnd) { + return new LocalDeclaration(localDeclarationName, sourceStart, sourceEnd); +} + +public CompilationUnitDeclaration dietParse(ICompilationUnit sourceUnit, CompilationResult compilationResult) { + + CompilationUnitDeclaration parsedUnit; + boolean old = this.diet; + try { + this.diet = true; + parsedUnit = parse(sourceUnit, compilationResult); + } + finally { + this.diet = old; + } + return parsedUnit; +} +protected void dispatchDeclarationInto(int length) { + /* they are length on astStack that should go into + methods fields constructors lists of the typeDecl + + Return if there is a constructor declaration in the methods declaration */ + + + // Looks for the size of each array . + + if (length == 0) + return; + int[] flag = new int[length + 1]; //plus one -- see + int size1 = 0, size2 = 0, size3 = 0; + for (int i = length - 1; i >= 0; i--) { + ASTNode astNode = this.astStack[this.astPtr--]; + if (astNode instanceof AbstractMethodDeclaration) { + //methods and constructors have been regrouped into one single list + flag[i] = 3; + size2++; + } else { + if (astNode instanceof TypeDeclaration) { + flag[i] = 4; + size3++; + } else { + //field + flag[i] = 1; + size1++; + } + } + } + + //arrays creation + TypeDeclaration typeDecl = (TypeDeclaration) this.astStack[this.astPtr]; + if (size1 != 0) + typeDecl.fields = new FieldDeclaration[size1]; + if (size2 != 0) + typeDecl.methods = new AbstractMethodDeclaration[size2]; + if (size3 != 0) + typeDecl.memberTypes = new TypeDeclaration[size3]; + + //arrays fill up + size1 = size2 = size3 = 0; + int flagI = flag[0], start = 0; + int length2; + for (int end = 0; end <= length; end++) // the plus one allows to + { + if (flagI != flag[end]) //treat the last element as a ended flag..... + { //array copy + switch (flagI) { + case 1 : + size1 += (length2 = end - start); + System.arraycopy( + this.astStack, + this.astPtr + start + 1, + typeDecl.fields, + size1 - length2, + length2); + break; + case 3 : + size2 += (length2 = end - start); + System.arraycopy( + this.astStack, + this.astPtr + start + 1, + typeDecl.methods, + size2 - length2, + length2); + break; + case 4 : + size3 += (length2 = end - start); + System.arraycopy( + this.astStack, + this.astPtr + start + 1, + typeDecl.memberTypes, + size3 - length2, + length2); + break; + } + flagI = flag[start = end]; + } + } + + if (typeDecl.memberTypes != null) { + for (int i = typeDecl.memberTypes.length - 1; i >= 0; i--) { + typeDecl.memberTypes[i].enclosingType = typeDecl; + } + } +} +protected CompilationUnitDeclaration endParse(int act) { + + this.lastAct = act; + + if (this.currentElement != null){ + this.currentElement.topElement().updateParseTree(); + if (VERBOSE_RECOVERY){ + System.out.print(Util.bind("parser.syntaxRecovery")); //$NON-NLS-1$ + System.out.println("--------------------------"); //$NON-NLS-1$ + System.out.println(this.compilationUnit); + System.out.println("----------------------------------"); //$NON-NLS-1$ + } + } else { + if (this.diet & VERBOSE_RECOVERY){ + System.out.print(Util.bind("parser.regularParse")); //$NON-NLS-1$ + System.out.println("--------------------------"); //$NON-NLS-1$ + System.out.println(this.compilationUnit); + System.out.println("----------------------------------"); //$NON-NLS-1$ + } + } + persistLineSeparatorPositions(); + for (int i = 0; i < this.scanner.foundTaskCount; i++){ + problemReporter().task( + new String(this.scanner.foundTaskTags[i]), + new String(this.scanner.foundTaskMessages[i]), + this.scanner.foundTaskPriorities[i] == null ? null : new String(this.scanner.foundTaskPriorities[i]), + this.scanner.foundTaskPositions[i][0], + this.scanner.foundTaskPositions[i][1]); + } + return this.compilationUnit; +} +/* + * Flush comments defined prior to a given positions. + * + * Note: comments are stacked in syntactical order + * + * Either answer given , or the end position of a comment line + * immediately following the (same line) + * + * e.g. + * void foo(){ + * } // end of method foo + */ + +public int flushCommentsDefinedPriorTo(int position) { + + int lastCommentIndex = this.scanner.commentPtr; + if (lastCommentIndex < 0) return position; // no comment + + // compute the index of the first obsolete comment + int index = lastCommentIndex; + int validCount = 0; + while (index >= 0){ + int commentEnd = this.scanner.commentStops[index]; + if (commentEnd < 0) commentEnd = -commentEnd; // negative end position for non-javadoc comments + if (commentEnd <= position){ + break; + } + index--; + validCount++; + } + // if the source at is immediately followed by a line comment, then + // flush this comment and shift to the comment end. + if (validCount > 0){ + int immediateCommentEnd = -this.scanner.commentStops[index+1]; //non-javadoc comment end positions are negative + if (immediateCommentEnd > 0){ // only tolerating non-javadoc comments + // is there any line break until the end of the immediate comment ? (thus only tolerating line comment) + immediateCommentEnd--; // comment end in one char too far + if (this.scanner.getLineNumber(position) == this.scanner.getLineNumber(immediateCommentEnd)){ + position = immediateCommentEnd; + validCount--; // flush this comment + index++; + } + } + } + + if (index < 0) return position; // no obsolete comment + + if (validCount > 0){ // move valid comment infos, overriding obsolete comment infos + System.arraycopy(this.scanner.commentStarts, index + 1, this.scanner.commentStarts, 0, validCount); + System.arraycopy(this.scanner.commentStops, index + 1, this.scanner.commentStops, 0, validCount); + } + this.scanner.commentPtr = validCount - 1; + return position; +} +public final int getFirstToken() { + // the first token is a virtual token that + // allows the parser to parse several goals + // even if they aren't LALR(1).... + // Goal ::= '++' CompilationUnit + // Goal ::= '--' MethodBody + // Goal ::= '==' ConstructorBody + // -- Initializer + // Goal ::= '>>' StaticInitializer + // Goal ::= '>>' Block + // -- error recovery + // Goal ::= '>>>' Headers + // Goal ::= '*' BlockStatements + // Goal ::= '*' MethodPushModifiersHeader + // -- JDOM + // Goal ::= '&&' FieldDeclaration + // Goal ::= '||' ImportDeclaration + // Goal ::= '?' PackageDeclaration + // Goal ::= '+' TypeDeclaration + // Goal ::= '/' GenericMethodDeclaration + // Goal ::= '&' ClassBodyDeclaration + // -- code snippet + // Goal ::= '%' Expression + // -- completion parser + // Goal ::= '!' ConstructorBlockStatementsopt + // Goal ::= '~' BlockStatementsopt + + return this.firstToken; +} +/* + * Answer back an array of sourceStart/sourceEnd positions of the available JavaDoc comments. + * The array is a flattened structure: 2*n entries with consecutives start and end positions. + * + * If no JavaDoc is available, then null is answered instead of an empty array. + * + * e.g. { 10, 20, 25, 45 } --> javadoc1 from 10 to 20, javadoc2 from 25 to 45 + */ +public int[] getJavaDocPositions() { + + int javadocCount = 0; + for (int i = 0, max = this.scanner.commentPtr; i <= max; i++){ + // javadoc only (non javadoc comment have negative end positions.) + if (this.scanner.commentStops[i] > 0){ + javadocCount++; + } + } + if (javadocCount == 0) return null; + + int[] positions = new int[2*javadocCount]; + int index = 0; + for (int i = 0, max = this.scanner.commentPtr; i <= max; i++){ + // javadoc only (non javadoc comment have negative end positions.) + if (this.scanner.commentStops[i] > 0){ + positions[index++] = this.scanner.commentStarts[i]; + positions[index++] = this.scanner.commentStops[i]-1; //stop is one over + } + } + return positions; +} + public void getMethodBodies(CompilationUnitDeclaration unit) { + //fill the methods bodies in order for the code to be generated + + if (unit == null) return; + + if (unit.ignoreMethodBodies) { + unit.ignoreFurtherInvestigation = true; + return; + // if initial diet parse did not work, no need to dig into method bodies. + } + + if ((unit.bits & ASTNode.HasAllMethodBodies) != 0) + return; //work already done ... + + //real parse of the method.... + char[] contents = unit.compilationResult.compilationUnit.getContents(); + this.scanner.setSource(contents); + + // save existing values to restore them at the end of the parsing process + // see bug 47079 for more details + int[] oldLineEnds = this.scanner.lineEnds; + int oldLinePtr = this.scanner.linePtr; + + final int[] lineSeparatorPositions = unit.compilationResult.lineSeparatorPositions; + this.scanner.lineEnds = lineSeparatorPositions; + this.scanner.linePtr = lineSeparatorPositions.length - 1; + + if (this.javadocParser != null && this.javadocParser.checkDocComment) { + this.javadocParser.scanner.setSource(contents); + } + if (unit.types != null) { + for (int i = unit.types.length; --i >= 0;) + unit.types[i].parseMethod(this, unit); + } + + // tag unit has having read bodies + unit.bits |= ASTNode.HasAllMethodBodies; + + // this is done to prevent any side effects on the compilation unit result + // line separator positions array. + this.scanner.lineEnds = oldLineEnds; + this.scanner.linePtr = oldLinePtr; + } +protected TypeReference getTypeReference(int dim) { /* build a Reference on a variable that may be qualified or not +This variable is a type reference and dim will be its dimensions*/ + + int length; + TypeReference ref; + if ((length = this.identifierLengthStack[this.identifierLengthPtr--]) == 1) { + // single variable reference + if (dim == 0) { + ref = + new SingleTypeReference( + this.identifierStack[this.identifierPtr], + this.identifierPositionStack[this.identifierPtr--]); + } else { + ref = + new ArrayTypeReference( + this.identifierStack[this.identifierPtr], + dim, + this.identifierPositionStack[this.identifierPtr--]); + ref.sourceEnd = this.endPosition; + } + } else { + if (length < 0) { //flag for precompiled type reference on base types + ref = TypeReference.baseTypeReference(-length, dim); + ref.sourceStart = this.intStack[this.intPtr--]; + if (dim == 0) { + ref.sourceEnd = this.intStack[this.intPtr--]; + } else { + this.intPtr--; + ref.sourceEnd = this.endPosition; + } + } else { //Qualified variable reference + char[][] tokens = new char[length][]; + this.identifierPtr -= length; + long[] positions = new long[length]; + System.arraycopy(this.identifierStack, this.identifierPtr + 1, tokens, 0, length); + System.arraycopy( + this.identifierPositionStack, + this.identifierPtr + 1, + positions, + 0, + length); + if (dim == 0) { + ref = new QualifiedTypeReference(tokens, positions); + } else { + ref = new ArrayQualifiedTypeReference(tokens, dim, positions); + ref.sourceEnd = this.endPosition; + } + } + } + return ref; +} +protected Expression getTypeReference(Expression exp) { + + exp.bits &= ~ASTNode.RestrictiveFlagMASK; + exp.bits |= TYPE; + return exp; +} +protected NameReference getUnspecifiedReference() { + /* build a (unspecified) NameReference which may be qualified*/ + + int length; + NameReference ref; + if ((length = this.identifierLengthStack[this.identifierLengthPtr--]) == 1) + // single variable reference + ref = + new SingleNameReference( + this.identifierStack[this.identifierPtr], + this.identifierPositionStack[this.identifierPtr--]); + else + //Qualified variable reference + { + char[][] tokens = new char[length][]; + this.identifierPtr -= length; + System.arraycopy(this.identifierStack, this.identifierPtr + 1, tokens, 0, length); + long[] positions = new long[length]; + System.arraycopy(this.identifierPositionStack, this.identifierPtr + 1, positions, 0, length); + ref = + new QualifiedNameReference(tokens, + positions, + (int) (this.identifierPositionStack[this.identifierPtr + 1] >> 32), // sourceStart + (int) this.identifierPositionStack[this.identifierPtr + length]); // sourceEnd + } + return ref; +} +protected NameReference getUnspecifiedReferenceOptimized() { + /* build a (unspecified) NameReference which may be qualified + The optimization occurs for qualified reference while we are + certain in this case the last item of the qualified name is + a field access. This optimization is IMPORTANT while it results + that when a NameReference is build, the type checker should always + look for that it is not a type reference */ + + int length; + NameReference ref; + if ((length = this.identifierLengthStack[this.identifierLengthPtr--]) == 1) { + // single variable reference + ref = + new SingleNameReference( + this.identifierStack[this.identifierPtr], + this.identifierPositionStack[this.identifierPtr--]); + ref.bits &= ~ASTNode.RestrictiveFlagMASK; + ref.bits |= LOCAL | FIELD; + return ref; + } + + //Qualified-variable-reference + //In fact it is variable-reference DOT field-ref , but it would result in a type + //conflict tha can be only reduce by making a superclass (or inetrface ) between + //nameReference and FiledReference or putting FieldReference under NameReference + //or else..........This optimisation is not really relevant so just leave as it is + + char[][] tokens = new char[length][]; + this.identifierPtr -= length; + System.arraycopy(this.identifierStack, this.identifierPtr + 1, tokens, 0, length); + long[] positions = new long[length]; + System.arraycopy(this.identifierPositionStack, this.identifierPtr + 1, positions, 0, length); + ref = new QualifiedNameReference( + tokens, + positions, + (int) (this.identifierPositionStack[this.identifierPtr + 1] >> 32), // sourceStart + (int) this.identifierPositionStack[this.identifierPtr + length]); // sourceEnd + ref.bits &= ~ASTNode.RestrictiveFlagMASK; + ref.bits |= LOCAL | FIELD; + return ref; +} +public void goForBlockStatementsopt() { + //tells the scanner to go for block statements opt parsing + + this.firstToken = TokenNameTWIDDLE; + this.scanner.recordLineSeparator = false; +} +public void goForBlockStatementsOrCatchHeader() { + //tells the scanner to go for block statements or method headers parsing + + this.firstToken = TokenNameMULTIPLY; + this.scanner.recordLineSeparator = false; +} +public void goForClassBodyDeclarations() { + //tells the scanner to go for any body declarations parsing + + this.firstToken = TokenNameAND; + this.scanner.recordLineSeparator = true; +} +public void goForCompilationUnit(){ + //tells the scanner to go for compilation unit parsing + + this.firstToken = TokenNamePLUS_PLUS ; + this.scanner.linePtr = -1; + this.scanner.foundTaskCount = 0; + this.scanner.recordLineSeparator = true; + this.scanner.currentLine= null; +} +public void goForExpression() { + //tells the scanner to go for an expression parsing + + this.firstToken = TokenNameREMAINDER; + this.scanner.recordLineSeparator = true; // recovery goals must record line separators +} +public void goForFieldDeclaration(){ + //tells the scanner to go for field declaration parsing + + this.firstToken = TokenNameAND_AND ; + this.scanner.recordLineSeparator = true; +} +public void goForGenericMethodDeclaration(){ + //tells the scanner to go for generic method declarations parsing + + this.firstToken = TokenNameDIVIDE; + this.scanner.recordLineSeparator = true; +} +public void goForHeaders(){ + //tells the scanner to go for headers only parsing + + this.firstToken = TokenNameUNSIGNED_RIGHT_SHIFT; + this.scanner.recordLineSeparator = true; // recovery goals must record line separators +} +public void goForImportDeclaration(){ + //tells the scanner to go for import declaration parsing + + this.firstToken = TokenNameOR_OR ; + this.scanner.recordLineSeparator = true; +} +public void goForInitializer(){ + //tells the scanner to go for initializer parsing + + this.firstToken = TokenNameRIGHT_SHIFT ; + this.scanner.recordLineSeparator = false; +} +public void goForMethodBody(){ + //tells the scanner to go for method body parsing + + this.firstToken = TokenNameMINUS_MINUS ; + this.scanner.recordLineSeparator = false; +} +public void goForPackageDeclaration() { + //tells the scanner to go for package declaration parsing + + this.firstToken = TokenNameQUESTION; + this.scanner.recordLineSeparator = true; +} +public void goForTypeDeclaration() { + //tells the scanner to go for type (interface or class) declaration parsing + + this.firstToken = TokenNamePLUS; + this.scanner.recordLineSeparator = true; +} +protected void ignoreExpressionAssignment() { + // Assignment ::= InvalidArrayInitializerAssignement + // encoded operator would be: this.intStack[this.intPtr] + this.intPtr--; + ArrayInitializer arrayInitializer = (ArrayInitializer) this.expressionStack[this.expressionPtr--]; + this.expressionLengthPtr -- ; + // report a syntax error and abort parsing + problemReporter().arrayConstantsOnlyInArrayInitializers(arrayInitializer.sourceStart, arrayInitializer.sourceEnd); +} +protected void ignoreInterfaceDeclaration() { + // BlockStatement ::= InvalidInterfaceDeclaration + //InterfaceDeclaration ::= Modifiersopt 'interface' 'Identifier' ExtendsInterfacesopt InterfaceHeader InterfaceBody + + // length declarations + int length; + if ((length = this.astLengthStack[this.astLengthPtr--]) != 0) { + //there are length declarations + //dispatch according to the type of the declarations + dispatchDeclarationInto(length); + } + + flushCommentsDefinedPriorTo(this.endStatementPosition); + + // report the problem and continue parsing + TypeDeclaration typeDecl = (TypeDeclaration) this.astStack[this.astPtr]; + typeDecl.bodyEnd = this.endStatementPosition; + problemReporter().cannotDeclareLocalInterface(typeDecl.name, typeDecl.sourceStart, typeDecl.sourceEnd); + + // mark initializers with local type mark if needed + markInitializersWithLocalType(typeDecl); + + // remove the ast node created in interface header + this.astPtr--; + pushOnAstLengthStack(-1); + concatNodeLists(); +} +protected void ignoreInvalidConstructorDeclaration(boolean hasBody) { + // InvalidConstructorDeclaration ::= ConstructorHeader ConstructorBody ==> true + // InvalidConstructorDeclaration ::= ConstructorHeader ';' ==> false + + /* + astStack : modifiers arguments throws statements + identifierStack : name + ==> + astStack : MethodDeclaration + identifierStack : + */ + if (hasBody) { + // pop the position of the { (body of the method) pushed in block decl + this.intPtr--; + } + + //statements + if (hasBody) { + this.realBlockPtr--; + } + + int length; + if (hasBody && ((length = this.astLengthStack[this.astLengthPtr--]) != 0)) { + this.astPtr -= length; + } + ConstructorDeclaration constructorDeclaration = (ConstructorDeclaration) this.astStack[this.astPtr]; + constructorDeclaration.bodyEnd = this.endStatementPosition; + constructorDeclaration.declarationSourceEnd = flushCommentsDefinedPriorTo(this.endStatementPosition); + if (!hasBody) { + constructorDeclaration.modifiers |= AccSemicolonBody; + } +} +protected void ignoreMethodBody() { + // InterfaceMemberDeclaration ::= InvalidMethodDeclaration + + /* + astStack : modifiers arguments throws statements + identifierStack : type name + intStack : dim dim dim + ==> + astStack : MethodDeclaration + identifierStack : + intStack : + */ + + // pop the position of the { (body of the method) pushed in block decl + this.intPtr--; + // retrieve end position of method declarator + + //statements + this.realBlockPtr--; + int length; + if ((length = this.astLengthStack[this.astLengthPtr--]) != 0) { + this.astPtr -= length; + } + + //watch for } that could be given as a unicode ! ( u007D is '}' ) + MethodDeclaration md = (MethodDeclaration) this.astStack[this.astPtr]; + md.bodyEnd = this.endPosition; + md.declarationSourceEnd = flushCommentsDefinedPriorTo(this.endStatementPosition); + + // report the problem and continue the parsing - narrowing the problem onto the method + problemReporter().abstractMethodNeedingNoBody(md); +} +public void initialize() { + //positionning the parser for a new compilation unit + //avoiding stack reallocation and all that.... + this.astPtr = -1; + this.astLengthPtr = -1; + this.expressionPtr = -1; + this.expressionLengthPtr = -1; + this.identifierPtr = -1; + this.identifierLengthPtr = -1; + this.intPtr = -1; + this.nestedMethod[this.nestedType = 0] = 0; // need to reset for further reuse + this.variablesCounter[this.nestedType] = 0; + this.dimensions = 0 ; + this.realBlockPtr = -1; + this.compilationUnit = null; + this.referenceContext = null; + this.endStatementPosition = 0; + + //remove objects from stack too, while the same parser/compiler couple is + //re-used between two compilations .... + + int astLength = this.astStack.length; + if (this.noAstNodes.length < astLength){ + this.noAstNodes = new ASTNode[astLength]; + //System.out.println("Resized AST stacks : "+ astLength); + + } + System.arraycopy(this.noAstNodes, 0, this.astStack, 0, astLength); + + int expressionLength = this.expressionStack.length; + if (this.noExpressions.length < expressionLength){ + this.noExpressions = new Expression[expressionLength]; + //System.out.println("Resized EXPR stacks : "+ expressionLength); + } + System.arraycopy(this.noExpressions, 0, this.expressionStack, 0, expressionLength); + + // reset scanner state + this.scanner.commentPtr = -1; + this.scanner.foundTaskCount = 0; + this.scanner.eofPosition = Integer.MAX_VALUE; + this.scanner.wasNonExternalizedStringLiteral = false; + this.scanner.nonNLSStrings = null; + this.scanner.currentLine = null; + + resetModifiers(); + + // recovery + this.lastCheckPoint = -1; + this.currentElement = null; + this.restartRecovery = false; + this.hasReportedError = false; + this.recoveredStaticInitializerStart = 0; + this.lastIgnoredToken = -1; + this.lastErrorEndPosition = -1; + this.listLength = 0; + + this.rBraceStart = 0; + this.rBraceEnd = 0; + this.rBraceSuccessorStart = 0; +} +public void initializeScanner(){ + this.scanner = new Scanner( + false /*comment*/, + false /*whitespace*/, + this.options.getSeverity(CompilerOptions.NonExternalizedString) != ProblemSeverities.Ignore /*nls*/, + this.options.sourceLevel /*sourceLevel*/, + this.options.taskTags/*taskTags*/, + this.options.taskPriorites/*taskPriorities*/, + this.options.isTaskCaseSensitive/*taskCaseSensitive*/); +} +public final static void initTables() throws java.io.IOException { + + final String prefix = FILEPREFIX; + int i = 0; + lhs = readTable(prefix + (++i) + ".rsc"); //$NON-NLS-1$ + char[] chars = readTable(prefix + (++i) + ".rsc"); //$NON-NLS-1$ + check_table = new short[chars.length]; + for (int c = chars.length; c-- > 0;) { + check_table[c] = (short) (chars[c] - 32768); + } + asb = readTable(prefix + (++i) + ".rsc"); //$NON-NLS-1$ + asr = readTable(prefix + (++i) + ".rsc"); //$NON-NLS-1$ + nasb = readTable(prefix + (++i) + ".rsc"); //$NON-NLS-1$ + nasr = readTable(prefix + (++i) + ".rsc"); //$NON-NLS-1$ + terminal_index = readTable(prefix + (++i) + ".rsc"); //$NON-NLS-1$ + non_terminal_index = readTable(prefix + (++i) + ".rsc"); //$NON-NLS-1$ + term_action = readTable(prefix + (++i) + ".rsc"); //$NON-NLS-1$ + + scope_prefix = readTable(prefix + (++i) + ".rsc"); //$NON-NLS-1$ + scope_suffix = readTable(prefix + (++i) + ".rsc"); //$NON-NLS-1$ + scope_lhs = readTable(prefix + (++i) + ".rsc"); //$NON-NLS-1$ + scope_state_set = readTable(prefix + (++i) + ".rsc"); //$NON-NLS-1$ + scope_rhs = readTable(prefix + (++i) + ".rsc"); //$NON-NLS-1$ + scope_state = readTable(prefix + (++i) + ".rsc"); //$NON-NLS-1$ + in_symb = readTable(prefix + (++i) + ".rsc"); //$NON-NLS-1$ + + rhs = readByteTable(prefix + (++i) + ".rsc"); //$NON-NLS-1$ + term_check = readByteTable(prefix + (++i) + ".rsc"); //$NON-NLS-1$ + scope_la = readByteTable(prefix + (++i) + ".rsc"); //$NON-NLS-1$ + + name = readNameTable(prefix + (++i) + ".rsc"); //$NON-NLS-1$ + readableName = readReadableNameTable(READABLE_NAMES); + + base_action = lhs; +} +public static int in_symbol(int state) { + return in_symb[original_state(state)]; +} +public final void jumpOverMethodBody() { + //on diet parsing.....do not buffer method statements + + //the scanner.diet is reinitialized to false + //automatically by the scanner once it has jumped over + //the statements + + if (this.diet && (this.dietInt == 0)) + this.scanner.diet = true; +} +protected void markEnclosingMemberWithLocalType() { + if (this.currentElement != null) return; // this is already done in the recovery code + for (int i = this.astPtr; i >= 0; i--) { + ASTNode node = this.astStack[i]; + if (node instanceof AbstractMethodDeclaration + || node instanceof FieldDeclaration + || node instanceof TypeDeclaration) { // mark type for now: all initializers will be marked when added to this type + node.bits |= ASTNode.HasLocalTypeMASK; + return; + } + } + // default to reference context (case of parse method body) + if (this.referenceContext instanceof AbstractMethodDeclaration + || this.referenceContext instanceof TypeDeclaration) { + ((ASTNode)this.referenceContext).bits |= ASTNode.HasLocalTypeMASK; + } +} +protected void markInitializersWithLocalType(TypeDeclaration type) { + if (type.fields == null || (type.bits & ASTNode.HasLocalTypeMASK) == 0) return; + for (int i = 0, length = type.fields.length; i < length; i++) { + FieldDeclaration field = type.fields[i]; + if (field instanceof Initializer) { + field.bits |= ASTNode.HasLocalTypeMASK; + } + } +} +/* + * Move checkpoint location (current implementation is moving it by one token) + * + * Answers true if successfully moved checkpoint (in other words, it did not attempt to move it + * beyond end of file). + */ +protected boolean moveRecoveryCheckpoint() { + + int pos = this.lastCheckPoint; + /* reset scanner, and move checkpoint by one token */ + this.scanner.startPosition = pos; + this.scanner.currentPosition = pos; + this.scanner.diet = false; // quit jumping over method bodies + + /* if about to restart, then no need to shift token */ + if (this.restartRecovery){ + this.lastIgnoredToken = -1; + this.scanner.currentLine = null; + return true; + } + + /* protect against shifting on an invalid token */ + this.lastIgnoredToken = this.nextIgnoredToken; + this.nextIgnoredToken = -1; + do { + try { + this.nextIgnoredToken = this.scanner.getNextToken(); + if(this.scanner.currentPosition == this.scanner.startPosition){ + this.scanner.currentPosition++; // on fake completion identifier + this.nextIgnoredToken = -1; + } + + } catch(InvalidInputException e){ + pos = this.scanner.currentPosition; + } + } while (this.nextIgnoredToken < 0); + + if (this.nextIgnoredToken == TokenNameEOF) { // no more recovery after this point + if (this.currentToken == TokenNameEOF) { // already tried one iteration on EOF + this.scanner.currentLine = null; + return false; + } + } + this.lastCheckPoint = this.scanner.currentPosition; + + /* reset scanner again to previous checkpoint location*/ + this.scanner.startPosition = pos; + this.scanner.currentPosition = pos; + this.scanner.commentPtr = -1; + this.scanner.foundTaskCount = 0; + this.scanner.currentLine = null; + + return true; + +/* + The following implementation moves the checkpoint location by one line: + + int pos = this.lastCheckPoint; + // reset scanner, and move checkpoint by one token + this.scanner.startPosition = pos; + this.scanner.currentPosition = pos; + this.scanner.diet = false; // quit jumping over method bodies + + // if about to restart, then no need to shift token + if (this.restartRecovery){ + this.lastIgnoredToken = -1; + return true; + } + + // protect against shifting on an invalid token + this.lastIgnoredToken = this.nextIgnoredToken; + this.nextIgnoredToken = -1; + + boolean wasTokenizingWhiteSpace = this.scanner.tokenizeWhiteSpace; + this.scanner.tokenizeWhiteSpace = true; + checkpointMove: + do { + try { + this.nextIgnoredToken = this.scanner.getNextToken(); + switch(this.nextIgnoredToken){ + case Scanner.TokenNameWHITESPACE : + if(this.scanner.getLineNumber(this.scanner.startPosition) + == this.scanner.getLineNumber(this.scanner.currentPosition)){ + this.nextIgnoredToken = -1; + } + break; + case TokenNameSEMICOLON : + case TokenNameLBRACE : + case TokenNameRBRACE : + break; + case TokenNameIdentifier : + if(this.scanner.currentPosition == this.scanner.startPosition){ + this.scanner.currentPosition++; // on fake completion identifier + } + default: + this.nextIgnoredToken = -1; + break; + case TokenNameEOF : + break checkpointMove; + } + } catch(InvalidInputException e){ + pos = this.scanner.currentPosition; + } + } while (this.nextIgnoredToken < 0); + this.scanner.tokenizeWhiteSpace = wasTokenizingWhiteSpace; + + if (this.nextIgnoredToken == TokenNameEOF) { // no more recovery after this point + if (this.currentToken == TokenNameEOF) { // already tried one iteration on EOF + return false; + } + } + this.lastCheckPoint = this.scanner.currentPosition; + + // reset scanner again to previous checkpoint location + this.scanner.startPosition = pos; + this.scanner.currentPosition = pos; + this.scanner.commentPtr = -1; + + return true; +*/ +} +protected MessageSend newMessageSend() { + // '(' ArgumentListopt ')' + // the arguments are on the expression stack + + MessageSend m = new MessageSend(); + int length; + if ((length = this.expressionLengthStack[this.expressionLengthPtr--]) != 0) { + this.expressionPtr -= length; + System.arraycopy( + this.expressionStack, + this.expressionPtr + 1, + m.arguments = new Expression[length], + 0, + length); + } + return m; +} +public static int nasi(int state) { + return nasb[original_state(state)]; +} +public static int ntAction(int state, int sym) { + return base_action[state + sym]; +} +private final void optimizedConcatNodeLists() { + /*back from a recursive loop. Virtualy group the + astNode into an array using astLengthStack*/ + + /* + * This is a case where you have two sublists into the astStack that you want + * to merge in one list. There is no action required on the astStack. The only + * thing you need to do is merge the two lengths specified on the astStackLength. + * The top two length are for example: + * ... p n + * and you want to result in a list like: + * ... n+p + * This means that the p could be equals to 0 in case there is no astNode pushed + * on the astStack. + * Look at the InterfaceMemberDeclarations for an example. + * This case optimizes the fact that p == 1. + */ + + this.astLengthStack[--this.astLengthPtr]++; +} +protected static int original_state(int state) { + return -base_check(state); +} +/*main loop of the automat +When a rule is reduced, the method consumeRule(int) is called with the number +of the consumed rule. When a terminal is consumed, the method consumeToken(int) is +called in order to remember (when needed) the consumed token */ +// (int)asr[asi(act)] +// name[symbol_index[currentKind]] +protected void parse() { + boolean isDietParse = this.diet; + int oldFirstToken = getFirstToken(); + this.hasError = false; + + this.hasReportedError = false; + int act = START_STATE; + this.stateStackTop = -1; + this.currentToken = getFirstToken(); + ProcessTerminals : for (;;) { + int stackLength = this.stack.length; + if (++this.stateStackTop >= stackLength) { + System.arraycopy( + this.stack, 0, + this.stack = new int[stackLength + StackIncrement], 0, + stackLength); + } + this.stack[this.stateStackTop] = act; + + act = tAction(act, this.currentToken); + + if (act == ERROR_ACTION || this.restartRecovery) { + int errorPos = this.scanner.currentPosition; + if (!this.hasReportedError){ + this.hasError = true; + } + if (resumeOnSyntaxError()) { + if (act == ERROR_ACTION) this.lastErrorEndPosition = errorPos; + act = START_STATE; + this.stateStackTop = -1; + this.currentToken = getFirstToken(); + continue ProcessTerminals; + } + act = ERROR_ACTION; + break ProcessTerminals; + } + if (act <= NUM_RULES) { + this.stateStackTop--; + + } else if (act > ERROR_ACTION) { /* shift-reduce */ + consumeToken(this.currentToken); + if (this.currentElement != null) this.recoveryTokenCheck(); + try { + this.currentToken = this.scanner.getNextToken(); + } catch(InvalidInputException e){ + if (!this.hasReportedError){ + this.problemReporter().scannerError(this, e.getMessage()); + this.hasReportedError = true; + } + this.lastCheckPoint = this.scanner.currentPosition; + this.restartRecovery = true; + } + act -= ERROR_ACTION; + + } else { + if (act < ACCEPT_ACTION) { /* shift */ + consumeToken(this.currentToken); + if (this.currentElement != null) this.recoveryTokenCheck(); + try{ + this.currentToken = this.scanner.getNextToken(); + } catch(InvalidInputException e){ + if (!this.hasReportedError){ + this.problemReporter().scannerError(this, e.getMessage()); + this.hasReportedError = true; + } + this.lastCheckPoint = this.scanner.currentPosition; + this.restartRecovery = true; + } + continue ProcessTerminals; + } + break ProcessTerminals; + } + ProcessNonTerminals : do { /* reduce */ + consumeRule(act); + this.stateStackTop -= (rhs[act] - 1); + act = ntAction(this.stack[this.stateStackTop], lhs[act]); + } while (act <= NUM_RULES); + } + endParse(act); + + if (this.reportSyntaxErrorIsRequired && this.hasError) { + reportSyntaxErrors(isDietParse, oldFirstToken); + } +} +// A P I +protected void reportSyntaxErrors(boolean isDietParse, int oldFirstToken) { + if(this.referenceContext instanceof MethodDeclaration) { + MethodDeclaration methodDeclaration = (MethodDeclaration) this.referenceContext; + if(methodDeclaration.errorInSignature){ + return; + } + } + this.compilationUnit.compilationResult.lineSeparatorPositions = this.scanner.getLineEnds(); + this.scanner.recordLineSeparator = false; + + int start = this.scanner.initialPosition; + int end = this.scanner.eofPosition <= Integer.MAX_VALUE ? this.scanner.eofPosition - 1 : this.scanner.eofPosition; + if(isDietParse) { + TypeDeclaration[] types = this.compilationUnit.types; + + int[][] intervalToSkip = org.eclipse.jdt.internal.compiler.parser.diagnose.RangeUtil.computeDietRange(types); + DiagnoseParser diagnoseParser = new DiagnoseParser(this, oldFirstToken, start, end, intervalToSkip[0], intervalToSkip[1], intervalToSkip[2]); + diagnoseParser.diagnoseParse(); + + reportSyntaxErrorsForSkippedMethod(types); + this.scanner.resetTo(start, end); + } else { + DiagnoseParser diagnoseParser = new DiagnoseParser(this, oldFirstToken, start, end); + diagnoseParser.diagnoseParse(); + } +} +private void reportSyntaxErrorsForSkippedMethod(TypeDeclaration[] types){ + if(types != null) { + for (int i = 0; i < types.length; i++) { + TypeDeclaration[] memberTypes = types[i].memberTypes; + if(memberTypes != null) { + reportSyntaxErrorsForSkippedMethod(memberTypes); + } + + AbstractMethodDeclaration[] methods = types[i].methods; + if(methods != null) { + for (int j = 0; j < methods.length; j++) { + AbstractMethodDeclaration method = methods[j]; + if(methods[j].errorInSignature) { + DiagnoseParser diagnoseParser = new DiagnoseParser(this, TokenNameDIVIDE, method.declarationSourceStart, method.declarationSourceEnd); + diagnoseParser.diagnoseParse(); + } + } + } + + FieldDeclaration[] fields = types[i].fields; + if (fields != null) { + int length = fields.length; + for (int j = 0; j < length; j++) { + if (fields[j] instanceof Initializer) { + Initializer initializer = (Initializer)fields[j]; + if(initializer.errorInSignature){ + DiagnoseParser diagnoseParser = new DiagnoseParser(this, TokenNameRIGHT_SHIFT, initializer.declarationSourceStart, initializer.declarationSourceEnd); + diagnoseParser.diagnoseParse(); + } + } + } + } + } + } +} +public void parse(ConstructorDeclaration cd, CompilationUnitDeclaration unit) { + parse(cd, unit, false); +} +public void parse(ConstructorDeclaration cd, CompilationUnitDeclaration unit, boolean recordLineSeparator) { + //only parse the method body of cd + //fill out its statements + + //convert bugs into parse error + + initialize(); + goForBlockStatementsopt(); + if (recordLineSeparator) { + this.scanner.recordLineSeparator = true; + } + this.nestedMethod[this.nestedType]++; + pushOnRealBlockStack(0); + + this.referenceContext = cd; + this.compilationUnit = unit; + + this.scanner.resetTo(cd.bodyStart, cd.bodyEnd); + try { + parse(); + } catch (AbortCompilation ex) { + this.lastAct = ERROR_ACTION; + } finally { + this.nestedMethod[this.nestedType]--; + } + + checkNonNLSAfterBodyEnd(cd.declarationSourceEnd); + + if (this.lastAct == ERROR_ACTION) { + initialize(); + return; + } + + //statements + cd.explicitDeclarations = this.realBlockStack[this.realBlockPtr--]; + int length; + if ((length = this.astLengthStack[this.astLengthPtr--]) != 0) { + this.astPtr -= length; + if (this.astStack[this.astPtr + 1] instanceof ExplicitConstructorCall) + //avoid a isSomeThing that would only be used here BUT what is faster between two alternatives ? + { + System.arraycopy( + this.astStack, + this.astPtr + 2, + cd.statements = new Statement[length - 1], + 0, + length - 1); + cd.constructorCall = (ExplicitConstructorCall) this.astStack[this.astPtr + 1]; + } else { //need to add explicitly the super(); + System.arraycopy( + this.astStack, + this.astPtr + 1, + cd.statements = new Statement[length], + 0, + length); + cd.constructorCall = SuperReference.implicitSuperConstructorCall(); + } + } else { + cd.constructorCall = SuperReference.implicitSuperConstructorCall(); + if (!containsComment(cd.bodyStart, cd.bodyEnd)) { + cd.bits |= ASTNode.UndocumentedEmptyBlockMASK; + } + } + + if (cd.constructorCall.sourceEnd == 0) { + cd.constructorCall.sourceEnd = cd.sourceEnd; + cd.constructorCall.sourceStart = cd.sourceStart; + } +} +// A P I + +public void parse( + FieldDeclaration field, + TypeDeclaration type, + CompilationUnitDeclaration unit, + char[] initializationSource) { + //only parse the initializationSource of the given field + + //convert bugs into parse error + + initialize(); + goForExpression(); + this.nestedMethod[this.nestedType]++; + + this.referenceContext = type; + this.compilationUnit = unit; + + this.scanner.setSource(initializationSource); + this.scanner.resetTo(0, initializationSource.length-1); + try { + parse(); + } catch (AbortCompilation ex) { + this.lastAct = ERROR_ACTION; + } finally { + this.nestedMethod[this.nestedType]--; + } + + if (this.lastAct == ERROR_ACTION) { + return; + } + + field.initialization = this.expressionStack[this.expressionPtr]; + + // mark field with local type if one was found during parsing + if ((type.bits & ASTNode.HasLocalTypeMASK) != 0) { + field.bits |= ASTNode.HasLocalTypeMASK; + } +} +// A P I + +public void parse( + Initializer initializer, + TypeDeclaration type, + CompilationUnitDeclaration unit) { + //only parse the method body of md + //fill out method statements + + //convert bugs into parse error + + initialize(); + goForBlockStatementsopt(); + this.nestedMethod[this.nestedType]++; + pushOnRealBlockStack(0); + + this.referenceContext = type; + this.compilationUnit = unit; + + this.scanner.resetTo(initializer.bodyStart, initializer.bodyEnd); // just on the beginning { + try { + parse(); + } catch (AbortCompilation ex) { + this.lastAct = ERROR_ACTION; + } finally { + this.nestedMethod[this.nestedType]--; + } + + checkNonNLSAfterBodyEnd(initializer.declarationSourceEnd); + + if (this.lastAct == ERROR_ACTION) { + return; + } + + //refill statements + initializer.block.explicitDeclarations = this.realBlockStack[this.realBlockPtr--]; + int length; + if ((length = this.astLengthStack[this.astLengthPtr--]) > 0) { + System.arraycopy(this.astStack, (this.astPtr -= length) + 1, initializer.block.statements = new Statement[length], 0, length); + } else { + // check whether this block at least contains some comment in it + if (!containsComment(initializer.block.sourceStart, initializer.block.sourceEnd)) { + initializer.block.bits |= ASTNode.UndocumentedEmptyBlockMASK; + } + } + + // mark initializer with local type if one was found during parsing + if ((type.bits & ASTNode.HasLocalTypeMASK) != 0) { + initializer.bits |= ASTNode.HasLocalTypeMASK; + } +} +// A P I + +public void parse(MethodDeclaration md, CompilationUnitDeclaration unit) { + //only parse the method body of md + //fill out method statements + + //convert bugs into parse error + + if (md.isAbstract()) + return; + if (md.isNative()) + return; + if ((md.modifiers & AccSemicolonBody) != 0) + return; + + initialize(); + goForBlockStatementsopt(); + this.nestedMethod[this.nestedType]++; + pushOnRealBlockStack(0); + + this.referenceContext = md; + this.compilationUnit = unit; + + this.scanner.resetTo(md.bodyStart, md.bodyEnd); + // reset the scanner to parser from { down to } + try { + parse(); + } catch (AbortCompilation ex) { + this.lastAct = ERROR_ACTION; + } finally { + this.nestedMethod[this.nestedType]--; + } + + checkNonNLSAfterBodyEnd(md.declarationSourceEnd); + + if (this.lastAct == ERROR_ACTION) { + return; + } + + //refill statements + md.explicitDeclarations = this.realBlockStack[this.realBlockPtr--]; + int length; + if ((length = this.astLengthStack[this.astLengthPtr--]) != 0) { + System.arraycopy( + this.astStack, + (this.astPtr -= length) + 1, + md.statements = new Statement[length], + 0, + length); + } else { + if (!containsComment(md.bodyStart, md.bodyEnd)) { + md.bits |= ASTNode.UndocumentedEmptyBlockMASK; + } + } +} +// A P I + +public CompilationUnitDeclaration parse( + ICompilationUnit sourceUnit, + CompilationResult compilationResult) { + // parses a compilation unit and manages error handling (even bugs....) + + return parse(sourceUnit, compilationResult, -1, -1/*parse without reseting the scanner*/); +} +// A P I + +public CompilationUnitDeclaration parse( + ICompilationUnit sourceUnit, + CompilationResult compilationResult, + int start, + int end) { + // parses a compilation unit and manages error handling (even bugs....) + + CompilationUnitDeclaration unit; + try { + /* automaton initialization */ + initialize(); + goForCompilationUnit(); + + /* scanners initialization */ + char[] contents = sourceUnit.getContents(); + this.scanner.setSource(contents); + if (end != -1) this.scanner.resetTo(start, end); + if (this.javadocParser != null && this.javadocParser.checkDocComment) { + this.javadocParser.scanner.setSource(contents); + if (end != -1) { + this.javadocParser.scanner.resetTo(start, end); + } + } + /* unit creation */ + this.referenceContext = + this.compilationUnit = + new CompilationUnitDeclaration( + this.problemReporter, + compilationResult, + this.scanner.source.length); + /* run automaton */ + parse(); + } finally { + unit = this.compilationUnit; + this.compilationUnit = null; // reset parser + // tag unit has having read bodies + if (!this.diet) unit.bits |= ASTNode.HasAllMethodBodies; + } + return unit; +} +public ASTNode[] parseClassBodyDeclarations(char[] source, int offset, int length, CompilationUnitDeclaration unit) { + /* automaton initialization */ + initialize(); + goForClassBodyDeclarations(); + /* scanner initialization */ + this.scanner.setSource(source); + this.scanner.resetTo(offset, offset + length - 1); + if (this.javadocParser != null && this.javadocParser.checkDocComment) { + this.javadocParser.scanner.setSource(source); + this.javadocParser.scanner.resetTo(offset, offset + length - 1); + } + + /* type declaration should be parsed as member type declaration */ + this.nestedType = 1; + + /* unit creation */ + this.referenceContext = unit; + this.compilationUnit = unit; + + /* run automaton */ + try { + parse(); + } catch (AbortCompilation ex) { + this.lastAct = ERROR_ACTION; + } + + if (this.lastAct == ERROR_ACTION) { + return null; + } + int astLength; + if ((astLength = this.astLengthStack[this.astLengthPtr--]) != 0) { + ASTNode[] result = new ASTNode[astLength]; + this.astPtr -= astLength; + System.arraycopy(this.astStack, this.astPtr + 1, result, 0, astLength); + return result; + } + return null; +} +public Expression parseExpression(char[] source, int offset, int length, CompilationUnitDeclaration unit) { + + initialize(); + goForExpression(); + this.nestedMethod[this.nestedType]++; + + this.referenceContext = unit; + this.compilationUnit = unit; + + this.scanner.setSource(source); + this.scanner.resetTo(offset, offset + length - 1); + try { + parse(); + } catch (AbortCompilation ex) { + this.lastAct = ERROR_ACTION; + } finally { + this.nestedMethod[this.nestedType]--; + } + + if (this.lastAct == ERROR_ACTION) { + return null; + } + + return this.expressionStack[this.expressionPtr]; +} +public void persistLineSeparatorPositions() { + if (this.scanner.recordLineSeparator) { + this.compilationUnit.compilationResult.lineSeparatorPositions = this.scanner.getLineEnds(); + } +} +/** + * Returns this parser's problem reporter initialized with its reference context. + * Also it is assumed that a problem is going to be reported, so initializes + * the compilation result's line positions. + * + * @return ProblemReporter + */ +public ProblemReporter problemReporter(){ + if (this.scanner.recordLineSeparator) { + this.compilationUnit.compilationResult.lineSeparatorPositions = this.scanner.getLineEnds(); + } + this.problemReporter.referenceContext = this.referenceContext; + return this.problemReporter; +} +protected void pushIdentifier() { + /*push the consumeToken on the identifier stack. + Increase the total number of identifier in the stack. + identifierPtr points on the next top */ + + int stackLength = this.identifierStack.length; + if (++this.identifierPtr >= stackLength) { + System.arraycopy( + this.identifierStack, 0, + this.identifierStack = new char[stackLength + 20][], 0, + stackLength); + System.arraycopy( + this.identifierPositionStack, 0, + this.identifierPositionStack = new long[stackLength + 20], 0, + stackLength); + } + this.identifierStack[this.identifierPtr] = this.scanner.getCurrentIdentifierSource(); + this.identifierPositionStack[this.identifierPtr] = + (((long) this.scanner.startPosition) << 32) + (this.scanner.currentPosition - 1); + + stackLength = this.identifierLengthStack.length; + if (++this.identifierLengthPtr >= stackLength) { + System.arraycopy( + this.identifierLengthStack, 0, + this.identifierLengthStack = new int[stackLength + 10], 0, + stackLength); + } + this.identifierLengthStack[this.identifierLengthPtr] = 1; +} +protected void pushIdentifier(int flag) { + /*push a special flag on the stack : + -zero stands for optional Name + -negative number for direct ref to base types. + identifierLengthPtr points on the top */ + + int stackLength = this.identifierLengthStack.length; + if (++this.identifierLengthPtr >= stackLength) { + System.arraycopy( + this.identifierLengthStack, 0, + this.identifierLengthStack = new int[stackLength + 10], 0, + stackLength); + } + this.identifierLengthStack[this.identifierLengthPtr] = flag; +} +protected void pushOnAstLengthStack(int pos) { + + int stackLength = this.astLengthStack.length; + if (++this.astLengthPtr >= stackLength) { + System.arraycopy( + this.astLengthStack, 0, + this.astLengthStack = new int[stackLength + StackIncrement], 0, + stackLength); + } + this.astLengthStack[this.astLengthPtr] = pos; +} +protected void pushOnAstStack(ASTNode node) { + /*add a new obj on top of the ast stack + astPtr points on the top*/ + + int stackLength = this.astStack.length; + if (++this.astPtr >= stackLength) { + System.arraycopy( + this.astStack, 0, + this.astStack = new ASTNode[stackLength + AstStackIncrement], 0, + stackLength); + this.astPtr = stackLength; + } + this.astStack[this.astPtr] = node; + + stackLength = this.astLengthStack.length; + if (++this.astLengthPtr >= stackLength) { + System.arraycopy( + this.astLengthStack, 0, + this.astLengthStack = new int[stackLength + AstStackIncrement], 0, + stackLength); + } + this.astLengthStack[this.astLengthPtr] = 1; +} +protected void pushOnExpressionStack(Expression expr) { + + int stackLength = this.expressionStack.length; + if (++this.expressionPtr >= stackLength) { + System.arraycopy( + this.expressionStack, 0, + this.expressionStack = new Expression[stackLength + ExpressionStackIncrement], 0, + stackLength); + } + this.expressionStack[this.expressionPtr] = expr; + + stackLength = this.expressionLengthStack.length; + if (++this.expressionLengthPtr >= stackLength) { + System.arraycopy( + this.expressionLengthStack, 0, + this.expressionLengthStack = new int[stackLength + ExpressionStackIncrement], 0, + stackLength); + } + this.expressionLengthStack[this.expressionLengthPtr] = 1; +} +protected void pushOnExpressionStackLengthStack(int pos) { + + int stackLength = this.expressionLengthStack.length; + if (++this.expressionLengthPtr >= stackLength) { + System.arraycopy( + this.expressionLengthStack, 0, + this.expressionLengthStack = new int[stackLength + StackIncrement], 0, + stackLength); + } + this.expressionLengthStack[this.expressionLengthPtr] = pos; +} +protected void pushOnIntStack(int pos) { + + int stackLength = this.intStack.length; + if (++this.intPtr >= stackLength) { + System.arraycopy( + this.intStack, 0, + this.intStack = new int[stackLength + StackIncrement], 0, + stackLength); + } + this.intStack[this.intPtr] = pos; +} +protected void pushOnRealBlockStack(int i){ + + int stackLength = this.realBlockStack.length; + if (++this.realBlockPtr >= stackLength) { + System.arraycopy( + this.realBlockStack, 0, + this.realBlockStack = new int[stackLength + StackIncrement], 0, + stackLength); + } + this.realBlockStack[this.realBlockPtr] = i; +} +protected static char[] readTable(String filename) throws java.io.IOException { + + //files are located at Parser.class directory + + InputStream stream = Parser.class.getResourceAsStream(filename); + if (stream == null) { + throw new java.io.IOException(Util.bind("parser.missingFile",filename)); //$NON-NLS-1$ + } + byte[] bytes = null; + try { + stream = new BufferedInputStream(stream); + bytes = Util.getInputStreamAsByteArray(stream, -1); + } finally { + try { + stream.close(); + } catch (IOException e) { + // ignore + } + } + + //minimal integrity check (even size expected) + int length = bytes.length; + if (length % 2 != 0) + throw new java.io.IOException(Util.bind("parser.corruptedFile",filename)); //$NON-NLS-1$ + + // convert bytes into chars + char[] chars = new char[length / 2]; + int i = 0; + int charIndex = 0; + + while (true) { + chars[charIndex++] = (char) (((bytes[i++] & 0xFF) << 8) + (bytes[i++] & 0xFF)); + if (i == length) + break; + } + return chars; +} +protected static byte[] readByteTable(String filename) throws java.io.IOException { + + //files are located at Parser.class directory + + InputStream stream = Parser.class.getResourceAsStream(filename); + if (stream == null) { + throw new java.io.IOException(Util.bind("parser.missingFile",filename)); //$NON-NLS-1$ + } + byte[] bytes = null; + try { + stream = new BufferedInputStream(stream); + bytes = Util.getInputStreamAsByteArray(stream, -1); + } finally { + try { + stream.close(); + } catch (IOException e) { + // ignore + } + } + return bytes; +} +protected static String[] readReadableNameTable(String filename) { + String[] result = new String[name.length]; + + ResourceBundle bundle; + try { + bundle = ResourceBundle.getBundle(filename, Locale.getDefault()); + } catch(MissingResourceException e) { + System.out.println("Missing resource : " + filename.replace('.', '/') + ".properties for locale " + Locale.getDefault()); //$NON-NLS-1$//$NON-NLS-2$ + throw e; + } + for (int i = 0; i < NT_OFFSET + 1; i++) { + result[i] = name[i]; + } + for (int i = NT_OFFSET; i < name.length; i++) { + try { + String n = bundle.getString(name[i]); + if(n != null && n.length() > 0) { + result[i] = n; + } else { + result[i] = name[i]; + } + } catch(MissingResourceException e) { + result[i] = name[i]; + } + } + return result; +} + +protected static String[] readNameTable(String filename) throws java.io.IOException { + char[] contents = readTable(filename); + char[][] nameAsChar = CharOperation.splitOn('\n', contents); + + String[] result = new String[nameAsChar.length + 1]; + result[0] = null; + for (int i = 0; i < nameAsChar.length; i++) { + result[i + 1] = new String(nameAsChar[i]); + } + + return result; +} +public void recoveryExitFromVariable() { + if(this.currentElement != null && this.currentElement.parent != null) { + if(this.currentElement instanceof RecoveredLocalVariable) { + + int end = ((RecoveredLocalVariable)this.currentElement).localDeclaration.sourceEnd; + this.currentElement.updateSourceEndIfNecessary(end); + this.currentElement = this.currentElement.parent; + } else if(this.currentElement instanceof RecoveredField + && !(this.currentElement instanceof RecoveredInitializer)) { + + int end = ((RecoveredField)this.currentElement).fieldDeclaration.sourceEnd; + this.currentElement.updateSourceEndIfNecessary(end); + this.currentElement = this.currentElement.parent; + } + } +} +/* Token check performed on every token shift once having entered + * recovery mode. + */ +public void recoveryTokenCheck() { + switch (this.currentToken) { + case TokenNameLBRACE : + RecoveredElement newElement = null; + if(!this.ignoreNextOpeningBrace) { + newElement = this.currentElement.updateOnOpeningBrace(this.scanner.startPosition - 1, this.scanner.currentPosition - 1); + } + this.lastCheckPoint = this.scanner.currentPosition; + if (newElement != null){ // null means nothing happened + this.restartRecovery = true; // opening brace detected + this.currentElement = newElement; + } + break; + + case TokenNameRBRACE : + this.rBraceStart = this.scanner.startPosition - 1; + this.rBraceEnd = this.scanner.currentPosition - 1; + this.endPosition = this.flushCommentsDefinedPriorTo(this.rBraceEnd); + newElement = + this.currentElement.updateOnClosingBrace(this.scanner.startPosition, this.rBraceEnd); + this.lastCheckPoint = this.scanner.currentPosition; + if (newElement != this.currentElement){ + this.currentElement = newElement; + } + break; + case TokenNameSEMICOLON : + this.endStatementPosition = this.scanner.currentPosition - 1; + this.endPosition = this.scanner.startPosition - 1; + // fall through + default : { + if (this.rBraceEnd > this.rBraceSuccessorStart && this.scanner.currentPosition != this.scanner.startPosition){ + this.rBraceSuccessorStart = this.scanner.startPosition; + } + break; + } + } + this.ignoreNextOpeningBrace = false; +} +protected void resetModifiers() { + this.modifiers = AccDefault; + this.modifiersSourceStart = -1; // <-- see comment into modifiersFlag(int) + this.scanner.commentPtr = -1; +} +/* + * Reset context so as to resume to regular parse loop + */ +protected void resetStacks() { + + this.astPtr = -1; + this.astLengthPtr = -1; + this.expressionPtr = -1; + this.expressionLengthPtr = -1; + this.identifierPtr = -1; + this.identifierLengthPtr = -1; + this.intPtr = -1; + this.nestedMethod[this.nestedType = 0] = 0; // need to reset for further reuse + this.variablesCounter[this.nestedType] = 0; + this.dimensions = 0 ; + this.realBlockStack[this.realBlockPtr = 0] = 0; + this.recoveredStaticInitializerStart = 0; + this.listLength = 0; + // Fix for http://dev.eclipse.org/bugs/show_bug.cgi?id=29365 + if (this.scanner != null) this.scanner.currentLine = null; +} +/* + * Reset context so as to resume to regular parse loop + * If unable to reset for resuming, answers false. + * + * Move checkpoint location, reset internal stacks and + * decide which grammar goal is activated. + */ +protected boolean resumeAfterRecovery() { + + // Reset javadoc before restart parsing after recovery + this.javadoc = null; + + // reset internal stacks + this.resetStacks(); + + /* attempt to move checkpoint location */ + if (!this.moveRecoveryCheckpoint()) { + return false; + } + + // only look for headers + if (this.referenceContext instanceof CompilationUnitDeclaration){ + goForHeaders(); + this.diet = true; // passed this point, will not consider method bodies + return true; + } + // does not know how to restart + return false; +} +/* + * Syntax error was detected. Will attempt to perform some recovery action in order + * to resume to the regular parse loop. + */ +protected boolean resumeOnSyntaxError() { + + /* request recovery initialization */ + if (this.currentElement == null){ + this.currentElement = + this.buildInitialRecoveryState(); // build some recovered elements + } + /* do not investigate deeper in recovery when no recovered element */ + if (this.currentElement == null) return false; + + /* manual forced recovery restart - after headers */ + if (this.restartRecovery){ + this.restartRecovery = false; + } + /* update recovery state with current error state of the parser */ + this.updateRecoveryState(); + + /* attempt to reset state in order to resume to parse loop */ + return this.resumeAfterRecovery(); +} +public static int tAction(int state, int sym) { + return term_action[term_check[base_action[state]+sym] == sym ? base_action[state] + sym : base_action[state]]; +} +public String toString() { + + String s = "identifierStack : char[][] = {"; //$NON-NLS-1$ + for (int i = 0; i <= this.identifierPtr; i++) { + s = s + "\"" + String.valueOf(this.identifierStack[i]) + "\","; //$NON-NLS-1$ //$NON-NLS-2$ + } + s = s + "}\n"; //$NON-NLS-1$ + + s = s + "identierLengthStack : int[] = {"; //$NON-NLS-1$ + for (int i = 0; i <= this.identifierLengthPtr; i++) { + s = s + this.identifierLengthStack[i] + ","; //$NON-NLS-1$ + } + s = s + "}\n"; //$NON-NLS-1$ + + s = s + "astLengthStack : int[] = {"; //$NON-NLS-1$ + for (int i = 0; i <= this.astLengthPtr; i++) { + s = s + this.astLengthStack[i] + ","; //$NON-NLS-1$ + } + s = s + "}\n"; //$NON-NLS-1$ + s = s + "astPtr : int = " + String.valueOf(this.astPtr) + "\n"; //$NON-NLS-1$ //$NON-NLS-2$ + + s = s + "intStack : int[] = {"; //$NON-NLS-1$ + for (int i = 0; i <= this.intPtr; i++) { + s = s + this.intStack[i] + ","; //$NON-NLS-1$ + } + s = s + "}\n"; //$NON-NLS-1$ + + s = s + "expressionLengthStack : int[] = {"; //$NON-NLS-1$ + for (int i = 0; i <= this.expressionLengthPtr; i++) { + s = s + this.expressionLengthStack[i] + ","; //$NON-NLS-1$ + } + s = s + "}\n"; //$NON-NLS-1$ + + s = s + "expressionPtr : int = " + String.valueOf(this.expressionPtr) + "\n"; //$NON-NLS-1$ //$NON-NLS-2$ + + s = s + "\n\n\n----------------Scanner--------------\n" + this.scanner.toString(); //$NON-NLS-1$ + return s; + +} +/* + * Update recovery state based on current parser/scanner state + */ +protected void updateRecoveryState() { + + /* expose parser state to recovery state */ + this.currentElement.updateFromParserState(); + + /* check and update recovered state based on current token, + this action is also performed when shifting token after recovery + got activated once. + */ + this.recoveryTokenCheck(); +} +protected void updateSourceDeclarationParts(int variableDeclaratorsCounter) { + //fields is a definition of fields that are grouped together like in + //public int[] a, b[], c + //which results into 3 fields. + + FieldDeclaration field; + int endTypeDeclarationPosition = + -1 + this.astStack[this.astPtr - variableDeclaratorsCounter + 1].sourceStart; + for (int i = 0; i < variableDeclaratorsCounter - 1; i++) { + //last one is special(see below) + field = (FieldDeclaration) this.astStack[this.astPtr - i - 1]; + field.endPart1Position = endTypeDeclarationPosition; + field.endPart2Position = -1 + this.astStack[this.astPtr - i].sourceStart; + } + //last one + (field = (FieldDeclaration) this.astStack[this.astPtr]).endPart1Position = + endTypeDeclarationPosition; + field.endPart2Position = field.declarationSourceEnd; + +} +protected void updateSourcePosition(Expression exp) { + //update the source Position of the expression + + //intStack : int int + //--> + //intStack : + + exp.sourceEnd = this.intStack[this.intPtr--]; + exp.sourceStart = this.intStack[this.intPtr--]; +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/ParserBasicInformation.java b/src/java/org/eclipse/jdt/internal/compiler/parser/ParserBasicInformation.java new file mode 100644 index 0000000..bdb077b --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/parser/ParserBasicInformation.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.parser; + +/*An interface that contains static declarations for some basic information + about the parser such as the number of rules in the grammar, the starting state, etc...*/ + +public interface ParserBasicInformation { + + public final static int + ERROR_SYMBOL = 105, + MAX_NAME_LENGTH = 36, + NUM_STATES = 597, + NT_OFFSET = 105, + SCOPE_UBOUND = 63, + SCOPE_SIZE = 64, + LA_STATE_OFFSET = 5981, + MAX_LA = 1, + NUM_RULES = 433, + NUM_TERMINALS = 105, + NUM_NON_TERMINALS = 203, + NUM_SYMBOLS = 308, + START_STATE = 529, + EOFT_SYMBOL = 54, + EOLT_SYMBOL = 54, + ACCEPT_ACTION = 5980, + ERROR_ACTION = 5981; +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/RecoveredBlock.java b/src/java/org/eclipse/jdt/internal/compiler/parser/RecoveredBlock.java new file mode 100644 index 0000000..9917bd9 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/parser/RecoveredBlock.java @@ -0,0 +1,330 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.parser; + +/** + * Internal block structure for parsing recovery + */ +import org.eclipse.jdt.core.compiler.*; +import org.eclipse.jdt.internal.compiler.ast.Argument; +import org.eclipse.jdt.internal.compiler.ast.ASTNode; +import org.eclipse.jdt.internal.compiler.ast.Block; +import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; +import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; +import org.eclipse.jdt.internal.compiler.ast.Statement; +import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; +import org.eclipse.jdt.internal.compiler.lookup.BaseTypes; +import org.eclipse.jdt.internal.compiler.lookup.CompilerModifiers; + +public class RecoveredBlock extends RecoveredStatement implements CompilerModifiers, TerminalTokens, BaseTypes { + + public Block blockDeclaration; + public RecoveredStatement[] statements; + public int statementCount; + public boolean preserveContent = false; + public RecoveredLocalVariable pendingArgument; + +public RecoveredBlock(Block block, RecoveredElement parent, int bracketBalance){ + super(block, parent, bracketBalance); + this.blockDeclaration = block; + this.foundOpeningBrace = true; +} +/* + * Record a nested block declaration + */ +public RecoveredElement add(Block nestedBlockDeclaration, int bracketBalanceValue) { + + /* do not consider a nested block starting passed the block end (if set) + it must be belonging to an enclosing block */ + if (this.blockDeclaration.sourceEnd != 0 + && nestedBlockDeclaration.sourceStart > this.blockDeclaration.sourceEnd){ + return this.parent.add(nestedBlockDeclaration, bracketBalanceValue); + } + + RecoveredBlock element = new RecoveredBlock(nestedBlockDeclaration, this, bracketBalanceValue); + + // if we have a pending Argument, promote it into the new block + if (this.pendingArgument != null){ + element.attach(this.pendingArgument); + this.pendingArgument = null; + } + this.attach(element); + if (nestedBlockDeclaration.sourceEnd == 0) return element; + return this; +} +/* + * Record a local declaration + */ +public RecoveredElement add(LocalDeclaration localDeclaration, int bracketBalanceValue) { + return this.add(localDeclaration, bracketBalanceValue, false); +} +/* + * Record a local declaration + */ +public RecoveredElement add(LocalDeclaration localDeclaration, int bracketBalanceValue, boolean delegatedByParent) { + + /* local variables inside method can only be final and non void */ +/* + char[][] localTypeName; + if ((localDeclaration.modifiers & ~AccFinal) != 0 // local var can only be final + || (localDeclaration.type == null) // initializer + || ((localTypeName = localDeclaration.type.getTypeName()).length == 1 // non void + && CharOperation.equals(localTypeName[0], VoidBinding.sourceName()))){ + + if (delegatedByParent){ + return this; //ignore + } else { + this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(localDeclaration.declarationSourceStart - 1)); + return this.parent.add(localDeclaration, bracketBalance); + } + } +*/ + /* do not consider a local variable starting passed the block end (if set) + it must be belonging to an enclosing block */ + if (this.blockDeclaration.sourceEnd != 0 + && localDeclaration.declarationSourceStart > this.blockDeclaration.sourceEnd){ + if (delegatedByParent) return this; //ignore + return this.parent.add(localDeclaration, bracketBalanceValue); + } + + RecoveredLocalVariable element = new RecoveredLocalVariable(localDeclaration, this, bracketBalanceValue); + + if (localDeclaration instanceof Argument){ + this.pendingArgument = element; + return this; + } + + this.attach(element); + if (localDeclaration.declarationSourceEnd == 0) return element; + return this; +} +/* + * Record a statement declaration + */ +public RecoveredElement add(Statement stmt, int bracketBalanceValue) { + return this.add(stmt, bracketBalanceValue, false); +} + +/* + * Record a statement declaration + */ +public RecoveredElement add(Statement stmt, int bracketBalanceValue, boolean delegatedByParent) { + + /* do not consider a nested block starting passed the block end (if set) + it must be belonging to an enclosing block */ + if (this.blockDeclaration.sourceEnd != 0 + && stmt.sourceStart > this.blockDeclaration.sourceEnd){ + if (delegatedByParent) return this; //ignore + return this.parent.add(stmt, bracketBalanceValue); + } + + RecoveredStatement element = new RecoveredStatement(stmt, this, bracketBalanceValue); + this.attach(element); + if (stmt.sourceEnd == 0) return element; + return this; +} +/* + * Addition of a type to an initializer (act like inside method body) + */ +public RecoveredElement add(TypeDeclaration typeDeclaration, int bracketBalanceValue) { + return this.add(typeDeclaration, bracketBalanceValue, false); +} +/* + * Addition of a type to an initializer (act like inside method body) + */ +public RecoveredElement add(TypeDeclaration typeDeclaration, int bracketBalanceValue, boolean delegatedByParent) { + + /* do not consider a type starting passed the block end (if set) + it must be belonging to an enclosing block */ + if (this.blockDeclaration.sourceEnd != 0 + && typeDeclaration.declarationSourceStart > this.blockDeclaration.sourceEnd){ + if (delegatedByParent) return this; //ignore + return this.parent.add(typeDeclaration, bracketBalanceValue); + } + + RecoveredStatement element = new RecoveredType(typeDeclaration, this, bracketBalanceValue); + this.attach(element); + if (typeDeclaration.declarationSourceEnd == 0) return element; + return this; +} +/* + * Attach a recovered statement + */ +void attach(RecoveredStatement recoveredStatement) { + + if (this.statements == null) { + this.statements = new RecoveredStatement[5]; + this.statementCount = 0; + } else { + if (this.statementCount == this.statements.length) { + System.arraycopy( + this.statements, + 0, + (this.statements = new RecoveredStatement[2 * this.statementCount]), + 0, + this.statementCount); + } + } + this.statements[this.statementCount++] = recoveredStatement; +} +/* + * Answer the associated parsed structure + */ +public ASTNode parseTree(){ + return this.blockDeclaration; +} +public String toString(int tab) { + StringBuffer result = new StringBuffer(tabString(tab)); + result.append("Recovered block:\n"); //$NON-NLS-1$ + this.blockDeclaration.print(tab + 1, result); + if (this.statements != null) { + for (int i = 0; i < this.statementCount; i++) { + result.append("\n"); //$NON-NLS-1$ + result.append(this.statements[i].toString(tab + 1)); + } + } + return result.toString(); +} +/* + * Rebuild a block from the nested structure which is in scope + */ +public Block updatedBlock(){ + + // if block was not marked to be preserved or empty, then ignore it + if (!this.preserveContent || this.statementCount == 0) return null; + + Statement[] updatedStatements = new Statement[this.statementCount]; + int updatedCount = 0; + + // only collect the non-null updated statements + for (int i = 0; i < this.statementCount; i++){ + Statement updatedStatement = this.statements[i].updatedStatement(); + if (updatedStatement != null){ + updatedStatements[updatedCount++] = updatedStatement; + } + } + if (updatedCount == 0) return null; // not interesting block + + // resize statement collection if necessary + if (updatedCount != this.statementCount){ + this.blockDeclaration.statements = new Statement[updatedCount]; + System.arraycopy(updatedStatements, 0, this.blockDeclaration.statements, 0, updatedCount); + } else { + this.blockDeclaration.statements = updatedStatements; + } + + return this.blockDeclaration; +} +/* + * Rebuild a statement from the nested structure which is in scope + */ +public Statement updatedStatement(){ + + return this.updatedBlock(); +} +/* + * A closing brace got consumed, might have closed the current element, + * in which case both the currentElement is exited + */ +public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd){ + if ((--this.bracketBalance <= 0) && (this.parent != null)){ + this.updateSourceEndIfNecessary(braceStart, braceEnd); + + /* if the block is the method body, then it closes the method too */ + RecoveredMethod method = enclosingMethod(); + if (method != null && method.methodBody == this){ + return this.parent.updateOnClosingBrace(braceStart, braceEnd); + } + RecoveredInitializer initializer = enclosingInitializer(); + if (initializer != null && initializer.initializerBody == this){ + return this.parent.updateOnClosingBrace(braceStart, braceEnd); + } + return this.parent; + } + return this; +} +/* + * An opening brace got consumed, might be the expected opening one of the current element, + * in which case the bodyStart is updated. + */ +public RecoveredElement updateOnOpeningBrace(int braceStart, int braceEnd){ + + // create a nested block + Block block = new Block(0); + block.sourceStart = parser().scanner.startPosition; + return this.add(block, 1); +} +/* + * Final update the corresponding parse node + */ +public void updateParseTree(){ + + this.updatedBlock(); +} +/* + * Rebuild a flattened block from the nested structure which is in scope + */ +public Statement updateStatement(){ + + // if block was closed or empty, then ignore it + if (this.blockDeclaration.sourceEnd != 0 || this.statementCount == 0) return null; + + Statement[] updatedStatements = new Statement[this.statementCount]; + int updatedCount = 0; + + // only collect the non-null updated statements + for (int i = 0; i < this.statementCount; i++){ + Statement updatedStatement = this.statements[i].updatedStatement(); + if (updatedStatement != null){ + updatedStatements[updatedCount++] = updatedStatement; + } + } + if (updatedCount == 0) return null; // not interesting block + + // resize statement collection if necessary + if (updatedCount != this.statementCount){ + this.blockDeclaration.statements = new Statement[updatedCount]; + System.arraycopy(updatedStatements, 0, this.blockDeclaration.statements, 0, updatedCount); + } else { + this.blockDeclaration.statements = updatedStatements; + } + + return this.blockDeclaration; +} + +/* + * Record a field declaration + */ +public RecoveredElement add(FieldDeclaration fieldDeclaration, int bracketBalanceValue) { + + /* local variables inside method can only be final and non void */ + char[][] fieldTypeName; + if ((fieldDeclaration.modifiers & ~AccFinal) != 0 // local var can only be final + || (fieldDeclaration.type == null) // initializer + || ((fieldTypeName = fieldDeclaration.type.getTypeName()).length == 1 // non void + && CharOperation.equals(fieldTypeName[0], VoidBinding.sourceName()))){ + this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(fieldDeclaration.declarationSourceStart - 1)); + return this.parent.add(fieldDeclaration, bracketBalanceValue); + } + + /* do not consider a local variable starting passed the block end (if set) + it must be belonging to an enclosing block */ + if (this.blockDeclaration.sourceEnd != 0 + && fieldDeclaration.declarationSourceStart > this.blockDeclaration.sourceEnd){ + return this.parent.add(fieldDeclaration, bracketBalanceValue); + } + + // ignore the added field, since indicates a local variable behind recovery point + // which thus got parsed as a field reference. This can happen if restarting after + // having reduced an assistNode to get the following context (see 1GEK7SG) + return this; +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/RecoveredElement.java b/src/java/org/eclipse/jdt/internal/compiler/parser/RecoveredElement.java new file mode 100644 index 0000000..bea72d2 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/parser/RecoveredElement.java @@ -0,0 +1,308 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.parser; + +/** + * Internal structure for parsing recovery + */ +import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.ASTNode; +import org.eclipse.jdt.internal.compiler.ast.Block; +import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; +import org.eclipse.jdt.internal.compiler.ast.ImportReference; +import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; +import org.eclipse.jdt.internal.compiler.ast.Statement; +import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; + +public class RecoveredElement { + + public RecoveredElement parent; + public int bracketBalance; + public boolean foundOpeningBrace; + protected Parser recoveringParser; +public RecoveredElement(RecoveredElement parent, int bracketBalance){ + this(parent, bracketBalance, null); +} +public RecoveredElement(RecoveredElement parent, int bracketBalance, Parser parser){ + this.parent = parent; + this.bracketBalance = bracketBalance; + this.recoveringParser = parser; +} +/* + * Record a method declaration + */ +public RecoveredElement add(AbstractMethodDeclaration methodDeclaration, int bracketBalanceValue) { + + /* default behavior is to delegate recording to parent if any */ + if (this.parent == null) return this; // ignore + this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(methodDeclaration.declarationSourceStart - 1)); + return this.parent.add(methodDeclaration, bracketBalanceValue); +} +/* + * Record a nested block declaration + */ +public RecoveredElement add(Block nestedBlockDeclaration, int bracketBalanceValue) { + + /* default behavior is to delegate recording to parent if any */ + if (this.parent == null) return this; // ignore + this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(nestedBlockDeclaration.sourceStart - 1)); + return this.parent.add(nestedBlockDeclaration, bracketBalanceValue); +} +/* + * Record a field declaration + */ +public RecoveredElement add(FieldDeclaration fieldDeclaration, int bracketBalanceValue) { + + /* default behavior is to delegate recording to parent if any */ + if (this.parent == null) return this; // ignore + this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(fieldDeclaration.declarationSourceStart - 1)); + return this.parent.add(fieldDeclaration, bracketBalanceValue); +} +/* + * Record an import reference + */ +public RecoveredElement add(ImportReference importReference, int bracketBalanceValue){ + + /* default behavior is to delegate recording to parent if any */ + if (this.parent == null) return this; // ignore + this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(importReference.declarationSourceStart - 1)); + return this.parent.add(importReference, bracketBalanceValue); +} +/* + * Record a local declaration + */ +public RecoveredElement add(LocalDeclaration localDeclaration, int bracketBalanceValue) { + + /* default behavior is to delegate recording to parent if any */ + if (this.parent == null) return this; // ignore + this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(localDeclaration.declarationSourceStart - 1)); + return this.parent.add(localDeclaration, bracketBalanceValue); +} +/* + * Record a statement + */ +public RecoveredElement add(Statement statement, int bracketBalanceValue) { + + /* default behavior is to delegate recording to parent if any */ + if (this.parent == null) return this; // ignore + this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(statement.sourceStart - 1)); + return this.parent.add(statement, bracketBalanceValue); +} +/* + * Record a type declaration + */ +public RecoveredElement add(TypeDeclaration typeDeclaration, int bracketBalanceValue){ + + /* default behavior is to delegate recording to parent if any */ + if (this.parent == null) return this; // ignore + this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(typeDeclaration.declarationSourceStart - 1)); + return this.parent.add(typeDeclaration, bracketBalanceValue); +} +/* + * Answer the depth of this element, considering the parent link. + */ +public int depth(){ + int depth = 0; + RecoveredElement current = this; + while ((current = current.parent) != null) depth++; + return depth; +} +/* + * Answer the enclosing method node, or null if none + */ +public RecoveredInitializer enclosingInitializer(){ + RecoveredElement current = this; + while (current != null){ + if (current instanceof RecoveredInitializer){ + return (RecoveredInitializer) current; + } + current = current.parent; + } + return null; +} +/* + * Answer the enclosing method node, or null if none + */ +public RecoveredMethod enclosingMethod(){ + RecoveredElement current = this; + while (current != null){ + if (current instanceof RecoveredMethod){ + return (RecoveredMethod) current; + } + current = current.parent; + } + return null; +} +/* + * Answer the enclosing type node, or null if none + */ +public RecoveredType enclosingType(){ + RecoveredElement current = this; + while (current != null){ + if (current instanceof RecoveredType){ + return (RecoveredType) current; + } + current = current.parent; + } + return null; +} +/* + * Answer the closest specified parser + */ +public Parser parser(){ + RecoveredElement current = this; + while (current != null){ + if (current.recoveringParser != null){ + return current.recoveringParser; + } + current = current.parent; + } + return null; +} +/* + * Answer the associated parsed structure + */ +public ASTNode parseTree(){ + return null; +} +/* + * Iterate the enclosing blocks and tag them so as to preserve their content + */ +public void preserveEnclosingBlocks(){ + RecoveredElement current = this; + while (current != null){ + if (current instanceof RecoveredBlock){ + ((RecoveredBlock)current).preserveContent = true; + } + if (current instanceof RecoveredType){ // for anonymous types + ((RecoveredType)current).preserveContent = true; + } + current = current.parent; + } +} +/* + * Answer the position of the previous line end if + * there is nothing but spaces in between it and the + * line end. Used to trim spaces on unclosed elements. + */ +public int previousAvailableLineEnd(int position){ + + Parser parser = this.parser(); + if (parser == null) return position; + + Scanner scanner = parser.scanner; + if (scanner.lineEnds == null) return position; + + int index = scanner.getLineNumber(position); + if (index < 2) return position; + int previousLineEnd = scanner.lineEnds[index-2]; + + char[] source = scanner.source; + for (int i = previousLineEnd+1; i < position; i++){ + if (!(source[i] == ' ' || source[i] == '\t')) return position; + } + return previousLineEnd; +} +/* + * Answer the very source end of the corresponding parse node + */ +public int sourceEnd(){ + return 0; +} +protected String tabString(int tab) { + StringBuffer result = new StringBuffer(); + for (int i = tab; i > 0; i--) { + result.append(" "); //$NON-NLS-1$ + } + return result.toString(); +} +/* + * Answer the top node + */ +public RecoveredElement topElement(){ + RecoveredElement current = this; + while (current.parent != null){ + current = current.parent; + } + return current; +} +public String toString() { + return toString(0); +} +public String toString(int tab) { + return super.toString(); +} +/* + * Answer the enclosing type node, or null if none + */ +public RecoveredType type(){ + RecoveredElement current = this; + while (current != null){ + if (current instanceof RecoveredType){ + return (RecoveredType) current; + } + current = current.parent; + } + return null; +} +/* + * Update the bodyStart of the corresponding parse node + */ +public void updateBodyStart(int bodyStart){ + this.foundOpeningBrace = true; +} +/* + * Update the corresponding parse node from parser state which + * is about to disappear because of restarting recovery + */ +public void updateFromParserState(){ + // default implementation: do nothing +} +/* + * A closing brace got consumed, might have closed the current element, + * in which case both the currentElement is exited + */ +public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd){ + if ((--this.bracketBalance <= 0) && (this.parent != null)){ + this.updateSourceEndIfNecessary(braceStart, braceEnd); + return this.parent; + } + return this; +} +/* + * An opening brace got consumed, might be the expected opening one of the current element, + * in which case the bodyStart is updated. + */ +/*public RecoveredElement updateOnOpeningBrace(int braceEnd){return null;}*/ +public RecoveredElement updateOnOpeningBrace(int braceStart, int braceEnd){ + + if (this.bracketBalance++ == 0){ + this.updateBodyStart(braceEnd + 1); + return this; + } + return null; // no update is necessary +} +/* + * Final update the corresponding parse node + */ +public void updateParseTree(){ + // default implementation: do nothing +} +/* + * Update the declarationSourceEnd of the corresponding parse node + */ +public void updateSourceEndIfNecessary(int braceStart, int braceEnd){ + // default implementation: do nothing +} +public void updateSourceEndIfNecessary(int sourceEnd){ + this.updateSourceEndIfNecessary(sourceEnd + 1, sourceEnd); +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/RecoveredField.java b/src/java/org/eclipse/jdt/internal/compiler/parser/RecoveredField.java new file mode 100644 index 0000000..4133b61 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/parser/RecoveredField.java @@ -0,0 +1,169 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.parser; + +/** + * Internal field structure for parsing recovery + */ +import org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference; +import org.eclipse.jdt.internal.compiler.ast.ASTNode; +import org.eclipse.jdt.internal.compiler.ast.Expression; +import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; +import org.eclipse.jdt.internal.compiler.ast.Statement; +import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; + +public class RecoveredField extends RecoveredElement { + + public FieldDeclaration fieldDeclaration; + boolean alreadyCompletedFieldInitialization; + + public RecoveredType[] anonymousTypes; + public int anonymousTypeCount; +public RecoveredField(FieldDeclaration fieldDeclaration, RecoveredElement parent, int bracketBalance){ + this(fieldDeclaration, parent, bracketBalance, null); +} +public RecoveredField(FieldDeclaration fieldDeclaration, RecoveredElement parent, int bracketBalance, Parser parser){ + super(parent, bracketBalance, parser); + this.fieldDeclaration = fieldDeclaration; + this.alreadyCompletedFieldInitialization = fieldDeclaration.initialization != null; +} +/* + * Record an expression statement if field is expecting an initialization expression, + * used for completion inside field initializers. + */ +public RecoveredElement add(Statement statement, int bracketBalanceValue) { + + if (this.alreadyCompletedFieldInitialization || !(statement instanceof Expression)) { + return super.add(statement, bracketBalanceValue); + } else { + this.alreadyCompletedFieldInitialization = true; + this.fieldDeclaration.initialization = (Expression)statement; + this.fieldDeclaration.declarationSourceEnd = statement.sourceEnd; + this.fieldDeclaration.declarationEnd = statement.sourceEnd; + return this; + } +} +/* + * Record a type declaration if this field is expecting an initialization expression + * and the type is an anonymous type. + * Used for completion inside field initializers. + */ +public RecoveredElement add(TypeDeclaration typeDeclaration, int bracketBalanceValue) { + + if (this.alreadyCompletedFieldInitialization + || ((typeDeclaration.bits & ASTNode.IsAnonymousTypeMASK) == 0) + || (this.fieldDeclaration.declarationSourceEnd != 0 && typeDeclaration.sourceStart > this.fieldDeclaration.declarationSourceEnd)) { + return super.add(typeDeclaration, bracketBalanceValue); + } else { + // Prepare anonymous type list + if (this.anonymousTypes == null) { + this.anonymousTypes = new RecoveredType[5]; + this.anonymousTypeCount = 0; + } else { + if (this.anonymousTypeCount == this.anonymousTypes.length) { + System.arraycopy( + this.anonymousTypes, + 0, + (this.anonymousTypes = new RecoveredType[2 * this.anonymousTypeCount]), + 0, + this.anonymousTypeCount); + } + } + // Store type declaration as an anonymous type + RecoveredType element = new RecoveredType(typeDeclaration, this, bracketBalanceValue); + this.anonymousTypes[this.anonymousTypeCount++] = element; + return element; + } +} +/* + * Answer the associated parsed structure + */ +public ASTNode parseTree(){ + return fieldDeclaration; +} +/* + * Answer the very source end of the corresponding parse node + */ +public int sourceEnd(){ + return this.fieldDeclaration.declarationSourceEnd; +} +public String toString(int tab){ + StringBuffer buffer = new StringBuffer(tabString(tab)); + buffer.append("Recovered field:\n"); //$NON-NLS-1$ + fieldDeclaration.print(tab + 1, buffer); + if (this.anonymousTypes != null) { + for (int i = 0; i < this.anonymousTypeCount; i++){ + buffer.append("\n"); //$NON-NLS-1$ + buffer.append(anonymousTypes[i].toString(tab + 1)); + } + } + return buffer.toString(); +} +public FieldDeclaration updatedFieldDeclaration(){ + + if (this.anonymousTypes != null && fieldDeclaration.initialization == null) { + for (int i = 0; i < this.anonymousTypeCount; i++){ + if (anonymousTypes[i].preserveContent){ + fieldDeclaration.initialization = this.anonymousTypes[i].updatedTypeDeclaration().allocation; + } + } + if (this.anonymousTypeCount > 0) fieldDeclaration.bits |= ASTNode.HasLocalTypeMASK; + } + return fieldDeclaration; +} +/* + * A closing brace got consumed, might have closed the current element, + * in which case both the currentElement is exited. + * + * Fields have no associated braces, thus if matches, then update parent. + */ +public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd){ + if (bracketBalance > 0){ // was an array initializer + bracketBalance--; + if (bracketBalance == 0) alreadyCompletedFieldInitialization = true; + return this; + } else if (bracketBalance == 0) { + alreadyCompletedFieldInitialization = true; + updateSourceEndIfNecessary(braceEnd - 1); + } + if (parent != null){ + return parent.updateOnClosingBrace(braceStart, braceEnd); + } + return this; +} +/* + * An opening brace got consumed, might be the expected opening one of the current element, + * in which case the bodyStart is updated. + */ +public RecoveredElement updateOnOpeningBrace(int braceStart, int braceEnd){ + if (fieldDeclaration.declarationSourceEnd == 0 + && fieldDeclaration.type instanceof ArrayTypeReference + && !alreadyCompletedFieldInitialization){ + bracketBalance++; + return null; // no update is necessary (array initializer) + } + // might be an array initializer + this.updateSourceEndIfNecessary(braceStart - 1, braceEnd - 1); + return this.parent.updateOnOpeningBrace(braceStart, braceEnd); +} +public void updateParseTree(){ + this.updatedFieldDeclaration(); +} +/* + * Update the declarationSourceEnd of the corresponding parse node + */ +public void updateSourceEndIfNecessary(int bodyStart, int bodyEnd){ + if (this.fieldDeclaration.declarationSourceEnd == 0) { + this.fieldDeclaration.declarationSourceEnd = bodyEnd; + this.fieldDeclaration.declarationEnd = bodyEnd; + } +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/RecoveredImport.java b/src/java/org/eclipse/jdt/internal/compiler/parser/RecoveredImport.java new file mode 100644 index 0000000..a86c81a --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/parser/RecoveredImport.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.parser; + +/** + * Internal import structure for parsing recovery + */ +import org.eclipse.jdt.internal.compiler.ast.ASTNode; +import org.eclipse.jdt.internal.compiler.ast.ImportReference; + +public class RecoveredImport extends RecoveredElement { + + public ImportReference importReference; +public RecoveredImport(ImportReference importReference, RecoveredElement parent, int bracketBalance){ + super(parent, bracketBalance); + this.importReference = importReference; +} +/* + * Answer the associated parsed structure + */ +public ASTNode parseTree(){ + return importReference; +} +/* + * Answer the very source end of the corresponding parse node + */ +public int sourceEnd(){ + return this.importReference.declarationSourceEnd; +} +public String toString(int tab) { + return tabString(tab) + "Recovered import: " + importReference.toString(); //$NON-NLS-1$ +} +public ImportReference updatedImportReference(){ + + return importReference; +} +public void updateParseTree(){ + this.updatedImportReference(); +} +/* + * Update the declarationSourceEnd of the corresponding parse node + */ +public void updateSourceEndIfNecessary(int bodyStart, int bodyEnd){ + if (this.importReference.declarationSourceEnd == 0) { + this.importReference.declarationSourceEnd = bodyEnd; + this.importReference.declarationEnd = bodyEnd; + } +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/RecoveredInitializer.java b/src/java/org/eclipse/jdt/internal/compiler/parser/RecoveredInitializer.java new file mode 100644 index 0000000..66d1aae --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/parser/RecoveredInitializer.java @@ -0,0 +1,237 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.parser; + +/** + * Internal initializer structure for parsing recovery + */ +import org.eclipse.jdt.core.compiler.*; +import org.eclipse.jdt.internal.compiler.ast.ASTNode; +import org.eclipse.jdt.internal.compiler.ast.Block; +import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; +import org.eclipse.jdt.internal.compiler.ast.Initializer; +import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; +import org.eclipse.jdt.internal.compiler.ast.Statement; +import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; +import org.eclipse.jdt.internal.compiler.lookup.BaseTypes; +import org.eclipse.jdt.internal.compiler.lookup.CompilerModifiers; + +public class RecoveredInitializer extends RecoveredField implements CompilerModifiers, TerminalTokens, BaseTypes { + + public RecoveredType[] localTypes; + public int localTypeCount; + + public RecoveredBlock initializerBody; + +public RecoveredInitializer(FieldDeclaration fieldDeclaration, RecoveredElement parent, int bracketBalance){ + this(fieldDeclaration, parent, bracketBalance, null); +} +public RecoveredInitializer(FieldDeclaration fieldDeclaration, RecoveredElement parent, int bracketBalance, Parser parser){ + super(fieldDeclaration, parent, bracketBalance, parser); + this.foundOpeningBrace = true; +} +/* + * Record a nested block declaration + */ +public RecoveredElement add(Block nestedBlockDeclaration, int bracketBalanceValue) { + + /* default behavior is to delegate recording to parent if any, + do not consider elements passed the known end (if set) + it must be belonging to an enclosing element + */ + if (fieldDeclaration.declarationSourceEnd > 0 + && nestedBlockDeclaration.sourceStart > fieldDeclaration.declarationSourceEnd){ + if (this.parent == null) return this; // ignore + return this.parent.add(nestedBlockDeclaration, bracketBalanceValue); + } + /* consider that if the opening brace was not found, it is there */ + if (!foundOpeningBrace){ + foundOpeningBrace = true; + this.bracketBalance++; + } + initializerBody = new RecoveredBlock(nestedBlockDeclaration, this, bracketBalanceValue); + if (nestedBlockDeclaration.sourceEnd == 0) return initializerBody; + return this; +} +/* + * Record a field declaration (act like inside method body) + */ +public RecoveredElement add(FieldDeclaration newFieldDeclaration, int bracketBalanceValue) { + + /* local variables inside initializer can only be final and non void */ + char[][] fieldTypeName; + if ((newFieldDeclaration.modifiers & ~AccFinal) != 0 /* local var can only be final */ + || (newFieldDeclaration.type == null) // initializer + || ((fieldTypeName = newFieldDeclaration.type.getTypeName()).length == 1 // non void + && CharOperation.equals(fieldTypeName[0], VoidBinding.sourceName()))){ + if (this.parent == null) return this; // ignore + this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(newFieldDeclaration.declarationSourceStart - 1)); + return this.parent.add(newFieldDeclaration, bracketBalanceValue); + } + + /* default behavior is to delegate recording to parent if any, + do not consider elements passed the known end (if set) + it must be belonging to an enclosing element + */ + if (this.fieldDeclaration.declarationSourceEnd > 0 + && newFieldDeclaration.declarationSourceStart > this.fieldDeclaration.declarationSourceEnd){ + if (this.parent == null) return this; // ignore + return this.parent.add(newFieldDeclaration, bracketBalanceValue); + } + // still inside initializer, treat as local variable + return this; // ignore +} +/* + * Record a local declaration - regular method should have been created a block body + */ +public RecoveredElement add(LocalDeclaration localDeclaration, int bracketBalanceValue) { + + /* do not consider a type starting passed the type end (if set) + it must be belonging to an enclosing type */ + if (fieldDeclaration.declarationSourceEnd != 0 + && localDeclaration.declarationSourceStart > fieldDeclaration.declarationSourceEnd){ + if (parent == null) return this; // ignore + return this.parent.add(localDeclaration, bracketBalanceValue); + } + /* method body should have been created */ + Block block = new Block(0); + block.sourceStart = ((Initializer)fieldDeclaration).sourceStart; + RecoveredElement element = this.add(block, 1); + return element.add(localDeclaration, bracketBalanceValue); +} +/* + * Record a statement - regular method should have been created a block body + */ +public RecoveredElement add(Statement statement, int bracketBalanceValue) { + + /* do not consider a statement starting passed the initializer end (if set) + it must be belonging to an enclosing type */ + if (fieldDeclaration.declarationSourceEnd != 0 + && statement.sourceStart > fieldDeclaration.declarationSourceEnd){ + if (parent == null) return this; // ignore + return this.parent.add(statement, bracketBalanceValue); + } + /* initializer body should have been created */ + Block block = new Block(0); + block.sourceStart = ((Initializer)fieldDeclaration).sourceStart; + RecoveredElement element = this.add(block, 1); + return element.add(statement, bracketBalanceValue); +} +public RecoveredElement add(TypeDeclaration typeDeclaration, int bracketBalanceValue) { + + /* do not consider a type starting passed the type end (if set) + it must be belonging to an enclosing type */ + if (fieldDeclaration.declarationSourceEnd != 0 + && typeDeclaration.declarationSourceStart > fieldDeclaration.declarationSourceEnd){ + if (parent == null) return this; // ignore + return this.parent.add(typeDeclaration, bracketBalanceValue); + } + if ((typeDeclaration.bits & ASTNode.IsLocalTypeMASK) != 0){ + /* method body should have been created */ + Block block = new Block(0); + block.sourceStart = ((Initializer)fieldDeclaration).sourceStart; + RecoveredElement element = this.add(block, 1); + return element.add(typeDeclaration, bracketBalanceValue); + } + if (localTypes == null) { + localTypes = new RecoveredType[5]; + localTypeCount = 0; + } else { + if (localTypeCount == localTypes.length) { + System.arraycopy( + localTypes, + 0, + (localTypes = new RecoveredType[2 * localTypeCount]), + 0, + localTypeCount); + } + } + RecoveredType element = new RecoveredType(typeDeclaration, this, bracketBalanceValue); + localTypes[localTypeCount++] = element; + + /* consider that if the opening brace was not found, it is there */ + if (!foundOpeningBrace){ + foundOpeningBrace = true; + this.bracketBalance++; + } + return element; +} +public String toString(int tab) { + StringBuffer result = new StringBuffer(tabString(tab)); + result.append("Recovered initializer:\n"); //$NON-NLS-1$ + this.fieldDeclaration.print(tab + 1, result); + if (this.initializerBody != null) { + result.append("\n"); //$NON-NLS-1$ + result.append(this.initializerBody.toString(tab + 1)); + } + return result.toString(); +} +public FieldDeclaration updatedFieldDeclaration(){ + + if (initializerBody != null){ + Block block = initializerBody.updatedBlock(); + if (block != null){ + ((Initializer)fieldDeclaration).block = block; + } + if (this.localTypeCount > 0) fieldDeclaration.bits |= ASTNode.HasLocalTypeMASK; + + } + if (fieldDeclaration.sourceEnd == 0){ + fieldDeclaration.sourceEnd = fieldDeclaration.declarationSourceEnd; + } + return fieldDeclaration; +} +/* + * A closing brace got consumed, might have closed the current element, + * in which case both the currentElement is exited + */ +public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd){ + if ((--bracketBalance <= 0) && (parent != null)){ + this.updateSourceEndIfNecessary(braceStart, braceEnd); + return parent; + } + return this; +} +/* + * An opening brace got consumed, might be the expected opening one of the current element, + * in which case the bodyStart is updated. + */ +public RecoveredElement updateOnOpeningBrace(int braceStart, int braceEnd){ + bracketBalance++; + return this; // request to restart +} +/* + * Update the declarationSourceEnd of the corresponding parse node + */ +public void updateSourceEndIfNecessary(int braceStart, int braceEnd){ + if (this.fieldDeclaration.declarationSourceEnd == 0) { + Initializer initializer = (Initializer)fieldDeclaration; + if(parser().rBraceSuccessorStart >= braceEnd) { + if (initializer.bodyStart < parser().rBraceEnd) { + initializer.declarationSourceEnd = parser().rBraceEnd; + } else { + initializer.declarationSourceEnd = initializer.bodyStart; + } + if (initializer.bodyStart < parser().rBraceStart) { + initializer.bodyEnd = parser().rBraceStart; + } else { + initializer.bodyEnd = initializer.bodyStart; + } + } else { + initializer.declarationSourceEnd = braceEnd; + initializer.bodyEnd = braceStart - 1; + } + if(initializer.block != null) { + initializer.block.sourceEnd = initializer.declarationSourceEnd; + } + } +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/RecoveredLocalVariable.java b/src/java/org/eclipse/jdt/internal/compiler/parser/RecoveredLocalVariable.java new file mode 100644 index 0000000..27b2fb2 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/parser/RecoveredLocalVariable.java @@ -0,0 +1,108 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.parser; + +/** + * Internal local variable structure for parsing recovery + */ +import org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference; +import org.eclipse.jdt.internal.compiler.ast.ASTNode; +import org.eclipse.jdt.internal.compiler.ast.Expression; +import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; +import org.eclipse.jdt.internal.compiler.ast.Statement; + +public class RecoveredLocalVariable extends RecoveredStatement { + + public LocalDeclaration localDeclaration; + boolean alreadyCompletedLocalInitialization; +public RecoveredLocalVariable(LocalDeclaration localDeclaration, RecoveredElement parent, int bracketBalance){ + super(localDeclaration, parent, bracketBalance); + this.localDeclaration = localDeclaration; + this.alreadyCompletedLocalInitialization = localDeclaration.initialization != null; +} +/* + * Record an expression statement if local variable is expecting an initialization expression. + */ +public RecoveredElement add(Statement stmt, int bracketBalanceValue) { + + if (this.alreadyCompletedLocalInitialization || !(stmt instanceof Expression)) { + return super.add(stmt, bracketBalanceValue); + } else { + this.alreadyCompletedLocalInitialization = true; + this.localDeclaration.initialization = (Expression)stmt; + this.localDeclaration.declarationSourceEnd = stmt.sourceEnd; + this.localDeclaration.declarationEnd = stmt.sourceEnd; + return this; + } +} +/* + * Answer the associated parsed structure + */ +public ASTNode parseTree(){ + return localDeclaration; +} +/* + * Answer the very source end of the corresponding parse node + */ +public int sourceEnd(){ + return this.localDeclaration.declarationSourceEnd; +} +public String toString(int tab) { + return tabString(tab) + "Recovered local variable:\n" + localDeclaration.print(tab + 1, new StringBuffer(10)); //$NON-NLS-1$ +} +public Statement updatedStatement(){ + return localDeclaration; +} +/* + * A closing brace got consumed, might have closed the current element, + * in which case both the currentElement is exited. + * + * Fields have no associated braces, thus if matches, then update parent. + */ +public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd){ + if (bracketBalance > 0){ // was an array initializer + bracketBalance--; + if (bracketBalance == 0) alreadyCompletedLocalInitialization = true; + return this; + } + if (parent != null){ + return parent.updateOnClosingBrace(braceStart, braceEnd); + } + return this; +} +/* + * An opening brace got consumed, might be the expected opening one of the current element, + * in which case the bodyStart is updated. + */ +public RecoveredElement updateOnOpeningBrace(int braceStart, int braceEnd){ + if (localDeclaration.declarationSourceEnd == 0 + && localDeclaration.type instanceof ArrayTypeReference + && !alreadyCompletedLocalInitialization){ + bracketBalance++; + return null; // no update is necessary (array initializer) + } + // might be an array initializer + this.updateSourceEndIfNecessary(braceStart - 1, braceEnd - 1); + return this.parent.updateOnOpeningBrace(braceStart, braceEnd); +} +public void updateParseTree(){ + this.updatedStatement(); +} +/* + * Update the declarationSourceEnd of the corresponding parse node + */ +public void updateSourceEndIfNecessary(int bodyStart, int bodyEnd){ + if (this.localDeclaration.declarationSourceEnd == 0) { + this.localDeclaration.declarationSourceEnd = bodyEnd; + this.localDeclaration.declarationEnd = bodyEnd; + } +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/RecoveredMethod.java b/src/java/org/eclipse/jdt/internal/compiler/parser/RecoveredMethod.java new file mode 100644 index 0000000..b76bf04 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/parser/RecoveredMethod.java @@ -0,0 +1,447 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.parser; + +import org.eclipse.jdt.core.compiler.*; +import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.Argument; +import org.eclipse.jdt.internal.compiler.ast.ASTNode; +import org.eclipse.jdt.internal.compiler.ast.Block; +import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration; +import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall; +import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; +import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; +import org.eclipse.jdt.internal.compiler.ast.Statement; +import org.eclipse.jdt.internal.compiler.ast.SuperReference; +import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; +import org.eclipse.jdt.internal.compiler.ast.TypeReference; +import org.eclipse.jdt.internal.compiler.lookup.BaseTypes; +import org.eclipse.jdt.internal.compiler.lookup.CompilerModifiers; + +/** + * Internal method structure for parsing recovery + */ + +public class RecoveredMethod extends RecoveredElement implements CompilerModifiers, TerminalTokens, BaseTypes { + + public AbstractMethodDeclaration methodDeclaration; + + public RecoveredType[] localTypes; + public int localTypeCount; + + public RecoveredBlock methodBody; + public boolean discardBody = true; + +public RecoveredMethod(AbstractMethodDeclaration methodDeclaration, RecoveredElement parent, int bracketBalance, Parser parser){ + super(parent, bracketBalance, parser); + this.methodDeclaration = methodDeclaration; + this.foundOpeningBrace = !bodyStartsAtHeaderEnd(); + if(this.foundOpeningBrace) { + this.bracketBalance++; + } +} +/* + * Record a nested block declaration + */ +public RecoveredElement add(Block nestedBlockDeclaration, int bracketBalanceValue) { + + /* default behavior is to delegate recording to parent if any, + do not consider elements passed the known end (if set) + it must be belonging to an enclosing element + */ + if (methodDeclaration.declarationSourceEnd > 0 + && nestedBlockDeclaration.sourceStart + > methodDeclaration.declarationSourceEnd){ + if (this.parent == null){ + return this; // ignore + } else { + return this.parent.add(nestedBlockDeclaration, bracketBalanceValue); + } + } + /* consider that if the opening brace was not found, it is there */ + if (!foundOpeningBrace){ + foundOpeningBrace = true; + this.bracketBalance++; + } + + methodBody = new RecoveredBlock(nestedBlockDeclaration, this, bracketBalanceValue); + if (nestedBlockDeclaration.sourceEnd == 0) return methodBody; + return this; +} +/* + * Record a field declaration + */ +public RecoveredElement add(FieldDeclaration fieldDeclaration, int bracketBalanceValue) { + + /* local variables inside method can only be final and non void */ + char[][] fieldTypeName; + if ((fieldDeclaration.modifiers & ~AccFinal) != 0 // local var can only be final + || (fieldDeclaration.type == null) // initializer + || ((fieldTypeName = fieldDeclaration.type.getTypeName()).length == 1 // non void + && CharOperation.equals(fieldTypeName[0], VoidBinding.sourceName()))){ + + if (this.parent == null){ + return this; // ignore + } else { + this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(fieldDeclaration.declarationSourceStart - 1)); + return this.parent.add(fieldDeclaration, bracketBalanceValue); + } + } + /* default behavior is to delegate recording to parent if any, + do not consider elements passed the known end (if set) + it must be belonging to an enclosing element + */ + if (methodDeclaration.declarationSourceEnd > 0 + && fieldDeclaration.declarationSourceStart + > methodDeclaration.declarationSourceEnd){ + if (this.parent == null){ + return this; // ignore + } else { + return this.parent.add(fieldDeclaration, bracketBalanceValue); + } + } + /* consider that if the opening brace was not found, it is there */ + if (!foundOpeningBrace){ + foundOpeningBrace = true; + this.bracketBalance++; + } + // still inside method, treat as local variable + return this; // ignore +} +/* + * Record a local declaration - regular method should have been created a block body + */ +public RecoveredElement add(LocalDeclaration localDeclaration, int bracketBalanceValue) { + + /* local variables inside method can only be final and non void */ +/* + char[][] localTypeName; + if ((localDeclaration.modifiers & ~AccFinal) != 0 // local var can only be final + || (localDeclaration.type == null) // initializer + || ((localTypeName = localDeclaration.type.getTypeName()).length == 1 // non void + && CharOperation.equals(localTypeName[0], VoidBinding.sourceName()))){ + + if (this.parent == null){ + return this; // ignore + } else { + this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(localDeclaration.declarationSourceStart - 1)); + return this.parent.add(localDeclaration, bracketBalance); + } + } +*/ + /* do not consider a type starting passed the type end (if set) + it must be belonging to an enclosing type */ + if (methodDeclaration.declarationSourceEnd != 0 + && localDeclaration.declarationSourceStart > methodDeclaration.declarationSourceEnd){ + + if (this.parent == null) { + return this; // ignore + } else { + return this.parent.add(localDeclaration, bracketBalanceValue); + } + } + if (methodBody == null){ + Block block = new Block(0); + block.sourceStart = methodDeclaration.bodyStart; + RecoveredElement currentBlock = this.add(block, 1); + if (this.bracketBalance > 0){ + for (int i = 0; i < this.bracketBalance - 1; i++){ + currentBlock = currentBlock.add(new Block(0), 1); + } + this.bracketBalance = 1; + } + return currentBlock.add(localDeclaration, bracketBalanceValue); + } + return methodBody.add(localDeclaration, bracketBalanceValue, true); +} +/* + * Record a statement - regular method should have been created a block body + */ +public RecoveredElement add(Statement statement, int bracketBalanceValue) { + + /* do not consider a type starting passed the type end (if set) + it must be belonging to an enclosing type */ + if (methodDeclaration.declarationSourceEnd != 0 + && statement.sourceStart > methodDeclaration.declarationSourceEnd){ + + if (this.parent == null) { + return this; // ignore + } else { + return this.parent.add(statement, bracketBalanceValue); + } + } + if (methodBody == null){ + Block block = new Block(0); + block.sourceStart = methodDeclaration.bodyStart; + RecoveredElement currentBlock = this.add(block, 1); + if (this.bracketBalance > 0){ + for (int i = 0; i < this.bracketBalance - 1; i++){ + currentBlock = currentBlock.add(new Block(0), 1); + } + this.bracketBalance = 1; + } + return currentBlock.add(statement, bracketBalanceValue); + } + return methodBody.add(statement, bracketBalanceValue, true); +} +public RecoveredElement add(TypeDeclaration typeDeclaration, int bracketBalanceValue) { + + /* do not consider a type starting passed the type end (if set) + it must be belonging to an enclosing type */ + if (methodDeclaration.declarationSourceEnd != 0 + && typeDeclaration.declarationSourceStart > methodDeclaration.declarationSourceEnd){ + + if (this.parent == null) { + return this; // ignore + } + return this.parent.add(typeDeclaration, bracketBalanceValue); + } + if ((typeDeclaration.bits & ASTNode.IsLocalTypeMASK) != 0){ + if (methodBody == null){ + Block block = new Block(0); + block.sourceStart = methodDeclaration.bodyStart; + this.add(block, 1); + } + return methodBody.add(typeDeclaration, bracketBalanceValue, true); + } + if (typeDeclaration.isInterface()) { + this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(typeDeclaration.declarationSourceStart - 1)); + if (this.parent == null) { + return this; // ignore + } + // close the constructor + return this.parent.add(typeDeclaration, bracketBalanceValue); + } + if (localTypes == null) { + localTypes = new RecoveredType[5]; + localTypeCount = 0; + } else { + if (localTypeCount == localTypes.length) { + System.arraycopy( + localTypes, + 0, + (localTypes = new RecoveredType[2 * localTypeCount]), + 0, + localTypeCount); + } + } + RecoveredType element = new RecoveredType(typeDeclaration, this, bracketBalanceValue); + localTypes[localTypeCount++] = element; + + /* consider that if the opening brace was not found, it is there */ + if (!foundOpeningBrace){ + foundOpeningBrace = true; + this.bracketBalance++; + } + return element; +} +public boolean bodyStartsAtHeaderEnd(){ + return methodDeclaration.bodyStart == methodDeclaration.sourceEnd+1; +} +/* + * Answer the associated parsed structure + */ +public ASTNode parseTree(){ + return methodDeclaration; +} +/* + * Answer the very source end of the corresponding parse node + */ +public int sourceEnd(){ + return this.methodDeclaration.declarationSourceEnd; +} +public String toString(int tab) { + StringBuffer result = new StringBuffer(tabString(tab)); + result.append("Recovered method:\n"); //$NON-NLS-1$ + this.methodDeclaration.print(tab + 1, result); + if (this.localTypes != null) { + for (int i = 0; i < this.localTypeCount; i++) { + result.append("\n"); //$NON-NLS-1$ + result.append(this.localTypes[i].toString(tab + 1)); + } + } + if (this.methodBody != null) { + result.append("\n"); //$NON-NLS-1$ + result.append(this.methodBody.toString(tab + 1)); + } + return result.toString(); +} +/* + * Update the bodyStart of the corresponding parse node + */ +public void updateBodyStart(int bodyStart){ + this.foundOpeningBrace = true; + this.methodDeclaration.bodyStart = bodyStart; +} +public AbstractMethodDeclaration updatedMethodDeclaration(){ + + if (methodBody != null){ + Block block = methodBody.updatedBlock(); + if (block != null){ + methodDeclaration.statements = block.statements; + + /* first statement might be an explict constructor call destinated to a special slot */ + if (methodDeclaration.isConstructor()) { + ConstructorDeclaration constructor = (ConstructorDeclaration)methodDeclaration; + if (methodDeclaration.statements != null + && methodDeclaration.statements[0] instanceof ExplicitConstructorCall){ + constructor.constructorCall = (ExplicitConstructorCall)methodDeclaration.statements[0]; + int length = methodDeclaration.statements.length; + System.arraycopy( + methodDeclaration.statements, + 1, + (methodDeclaration.statements = new Statement[length-1]), + 0, + length-1); + } + if (constructor.constructorCall == null){ // add implicit constructor call + constructor.constructorCall = SuperReference.implicitSuperConstructorCall(); + } + } + } + } + if (localTypeCount > 0) methodDeclaration.bits |= ASTNode.HasLocalTypeMASK; + return methodDeclaration; +} +/* + * Update the corresponding parse node from parser state which + * is about to disappear because of restarting recovery + */ +public void updateFromParserState(){ + + if(this.bodyStartsAtHeaderEnd()){ + Parser parser = this.parser(); + /* might want to recover arguments or thrown exceptions */ + if (parser.listLength > 0 && parser.astLengthPtr > 0){ // awaiting interface type references + /* has consumed the arguments - listed elements must be thrown exceptions */ + if (methodDeclaration.sourceEnd == parser.rParenPos) { + + // protection for bugs 15142 + int length = parser.astLengthStack[parser.astLengthPtr]; + int astPtr = parser.astPtr - length; + boolean canConsume = astPtr >= 0; + if(canConsume) { + if((!(parser.astStack[astPtr] instanceof AbstractMethodDeclaration))) { + canConsume = false; + } + for (int i = 1, max = length + 1; i < max; i++) { + if(!(parser.astStack[astPtr + i ] instanceof TypeReference)) { + canConsume = false; + } + } + } + if (canConsume){ + parser.consumeMethodHeaderThrowsClause(); + // will reset typeListLength to zero + // thus this check will only be performed on first errorCheck after void foo() throws X, Y, + } else { + parser.listLength = 0; + } + } else { + /* has not consumed arguments yet, listed elements must be arguments */ + if (parser.currentToken == TokenNameLPAREN || parser.currentToken == TokenNameSEMICOLON){ + /* if currentToken is parenthesis this last argument is a method/field signature */ + parser.astLengthStack[parser.astLengthPtr] --; + parser.astPtr --; + parser.listLength --; + parser.currentToken = 0; + } + int argLength = parser.astLengthStack[parser.astLengthPtr]; + int argStart = parser.astPtr - argLength + 1; + boolean needUpdateRParenPos = parser.rParenPos < parser.lParenPos; // 12387 : rParenPos will be used + // to compute bodyStart, and thus used to set next checkpoint. + int count; + for (count = 0; count < argLength; count++){ + Argument argument = (Argument)parser.astStack[argStart+count]; + /* cannot be an argument if non final */ + char[][] argTypeName = argument.type.getTypeName(); + if ((argument.modifiers & ~AccFinal) != 0 + || (argTypeName.length == 1 + && CharOperation.equals(argTypeName[0], VoidBinding.sourceName()))){ + parser.astLengthStack[parser.astLengthPtr] = count; + parser.astPtr = argStart+count-1; + parser.listLength = count; + parser.currentToken = 0; + break; + } + if (needUpdateRParenPos) parser.rParenPos = argument.sourceEnd + 1; + } + if (parser.listLength > 0 && parser.astLengthPtr > 0){ + + // protection for bugs 15142 + int length = parser.astLengthStack[parser.astLengthPtr]; + int astPtr = parser.astPtr - length; + boolean canConsume = astPtr >= 0; + if(canConsume) { + if((!(parser.astStack[astPtr] instanceof AbstractMethodDeclaration))) { + canConsume = false; + } + for (int i = 1, max = length + 1; i < max; i++) { + if(!(parser.astStack[astPtr + i ] instanceof Argument)) { + canConsume = false; + } + } + } + if(canConsume) { + parser.consumeMethodHeaderParameters(); + /* fix-up positions, given they were updated against rParenPos, which did not get set */ + if (parser.currentElement == this){ // parameter addition might have added an awaiting (no return type) method - see 1FVXQZ4 */ + methodDeclaration.sourceEnd = methodDeclaration.arguments[methodDeclaration.arguments.length-1].sourceEnd; + methodDeclaration.bodyStart = methodDeclaration.sourceEnd+1; + parser.lastCheckPoint = methodDeclaration.bodyStart; + } + } + } + } + } + } +} +/* + * An opening brace got consumed, might be the expected opening one of the current element, + * in which case the bodyStart is updated. + */ +public RecoveredElement updateOnOpeningBrace(int braceStart, int braceEnd){ + + /* in case the opening brace is close enough to the signature */ + if (bracketBalance == 0){ + /* + if (parser.scanner.searchLineNumber(methodDeclaration.sourceEnd) + != parser.scanner.searchLineNumber(braceEnd)){ + */ + switch(parser().lastIgnoredToken){ + case -1 : + case TokenNamethrows : + break; + default: + this.foundOpeningBrace = true; + bracketBalance = 1; // pretend the brace was already there + } + } + return super.updateOnOpeningBrace(braceStart, braceEnd); +} +public void updateParseTree(){ + this.updatedMethodDeclaration(); +} +/* + * Update the declarationSourceEnd of the corresponding parse node + */ +public void updateSourceEndIfNecessary(int braceStart, int braceEnd){ + if (this.methodDeclaration.declarationSourceEnd == 0) { + if(parser().rBraceSuccessorStart >= braceEnd) { + this.methodDeclaration.declarationSourceEnd = parser().rBraceEnd; + this.methodDeclaration.bodyEnd = parser().rBraceStart; + } else { + this.methodDeclaration.declarationSourceEnd = braceEnd; + this.methodDeclaration.bodyEnd = braceStart - 1; + } + } +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/RecoveredStatement.java b/src/java/org/eclipse/jdt/internal/compiler/parser/RecoveredStatement.java new file mode 100644 index 0000000..adbb79e --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/parser/RecoveredStatement.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.parser; + +/** + * Internal statement structure for parsing recovery + */ +import org.eclipse.jdt.internal.compiler.ast.ASTNode; +import org.eclipse.jdt.internal.compiler.ast.Statement; + +public class RecoveredStatement extends RecoveredElement { + + public Statement statement; +public RecoveredStatement(Statement statement, RecoveredElement parent, int bracketBalance){ + super(parent, bracketBalance); + this.statement = statement; +} +/* + * Answer the associated parsed structure + */ +public ASTNode parseTree(){ + return statement; +} +/* + * Answer the very source end of the corresponding parse node + */ +public int sourceEnd(){ + return this.statement.sourceEnd; +} +public String toString(int tab){ + return tabString(tab) + "Recovered statement:\n" + statement.print(tab + 1, new StringBuffer(10)); //$NON-NLS-1$ +} +public Statement updatedStatement(){ + return statement; +} +public void updateParseTree(){ + this.updatedStatement(); +} +/* + * Update the declarationSourceEnd of the corresponding parse node + */ +public void updateSourceEndIfNecessary(int bodyStart, int bodyEnd){ + if (this.statement.sourceEnd == 0) + this.statement.sourceEnd = bodyEnd; +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/RecoveredType.java b/src/java/org/eclipse/jdt/internal/compiler/parser/RecoveredType.java new file mode 100644 index 0000000..9ac355e --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/parser/RecoveredType.java @@ -0,0 +1,479 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.parser; + +import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.ASTNode; +import org.eclipse.jdt.internal.compiler.ast.Block; +import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; +import org.eclipse.jdt.internal.compiler.ast.Initializer; +import org.eclipse.jdt.internal.compiler.ast.Statement; +import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; +import org.eclipse.jdt.internal.compiler.ast.TypeReference; +import org.eclipse.jdt.internal.compiler.lookup.CompilerModifiers; + +/** + * Internal type structure for parsing recovery + */ + +public class RecoveredType extends RecoveredStatement implements TerminalTokens, CompilerModifiers { + public TypeDeclaration typeDeclaration; + + public RecoveredType[] memberTypes; + public int memberTypeCount; + public RecoveredField[] fields; + public int fieldCount; + public RecoveredMethod[] methods; + public int methodCount; + + public boolean preserveContent = false; // only used for anonymous types + public int bodyEnd; + +public RecoveredType(TypeDeclaration typeDeclaration, RecoveredElement parent, int bracketBalance){ + super(typeDeclaration, parent, bracketBalance); + this.typeDeclaration = typeDeclaration; + this.foundOpeningBrace = !bodyStartsAtHeaderEnd(); + if(this.foundOpeningBrace) { + this.bracketBalance++; + } +} +public RecoveredElement add(AbstractMethodDeclaration methodDeclaration, int bracketBalanceValue) { + + /* do not consider a method starting passed the type end (if set) + it must be belonging to an enclosing type */ + if (typeDeclaration.declarationSourceEnd != 0 + && methodDeclaration.declarationSourceStart > typeDeclaration.declarationSourceEnd){ + return this.parent.add(methodDeclaration, bracketBalanceValue); + } + + if (methods == null) { + methods = new RecoveredMethod[5]; + methodCount = 0; + } else { + if (methodCount == methods.length) { + System.arraycopy( + methods, + 0, + (methods = new RecoveredMethod[2 * methodCount]), + 0, + methodCount); + } + } + RecoveredMethod element = new RecoveredMethod(methodDeclaration, this, bracketBalanceValue, this.recoveringParser); + methods[methodCount++] = element; + + /* consider that if the opening brace was not found, it is there */ + if (!foundOpeningBrace){ + foundOpeningBrace = true; + this.bracketBalance++; + } + /* if method not finished, then method becomes current */ + if (methodDeclaration.declarationSourceEnd == 0) return element; + return this; +} +public RecoveredElement add(Block nestedBlockDeclaration,int bracketBalanceValue) { + int modifiers = AccDefault; + if(this.parser().recoveredStaticInitializerStart != 0) { + modifiers = AccStatic; + } + return this.add(new Initializer(nestedBlockDeclaration, modifiers), bracketBalanceValue); +} +public RecoveredElement add(FieldDeclaration fieldDeclaration, int bracketBalanceValue) { + + /* do not consider a field starting passed the type end (if set) + it must be belonging to an enclosing type */ + if (typeDeclaration.declarationSourceEnd != 0 + && fieldDeclaration.declarationSourceStart > typeDeclaration.declarationSourceEnd) { + return this.parent.add(fieldDeclaration, bracketBalanceValue); + } + if (fields == null) { + fields = new RecoveredField[5]; + fieldCount = 0; + } else { + if (fieldCount == fields.length) { + System.arraycopy( + fields, + 0, + (fields = new RecoveredField[2 * fieldCount]), + 0, + fieldCount); + } + } + RecoveredField element = fieldDeclaration.isField() + ? new RecoveredField(fieldDeclaration, this, bracketBalanceValue) + : new RecoveredInitializer(fieldDeclaration, this, bracketBalanceValue); + fields[fieldCount++] = element; + + /* consider that if the opening brace was not found, it is there */ + if (!foundOpeningBrace){ + foundOpeningBrace = true; + this.bracketBalance++; + } + /* if field not finished, then field becomes current */ + if (fieldDeclaration.declarationSourceEnd == 0) return element; + return this; +} +public RecoveredElement add(TypeDeclaration memberTypeDeclaration, int bracketBalanceValue) { + + /* do not consider a type starting passed the type end (if set) + it must be belonging to an enclosing type */ + if (typeDeclaration.declarationSourceEnd != 0 + && memberTypeDeclaration.declarationSourceStart > typeDeclaration.declarationSourceEnd){ + return this.parent.add(memberTypeDeclaration, bracketBalanceValue); + } + + if ((memberTypeDeclaration.bits & ASTNode.IsAnonymousTypeMASK) != 0){ + if (this.methodCount > 0) { + // add it to the last method body + RecoveredMethod lastMethod = this.methods[this.methodCount-1]; + lastMethod.methodDeclaration.bodyEnd = 0; // reopen method + lastMethod.methodDeclaration.declarationSourceEnd = 0; // reopen method + lastMethod.bracketBalance++; // expect one closing brace + return lastMethod.add(memberTypeDeclaration, bracketBalanceValue); + } else { + // ignore + return this; + } + } + + if (memberTypes == null) { + memberTypes = new RecoveredType[5]; + memberTypeCount = 0; + } else { + if (memberTypeCount == memberTypes.length) { + System.arraycopy( + memberTypes, + 0, + (memberTypes = new RecoveredType[2 * memberTypeCount]), + 0, + memberTypeCount); + } + } + RecoveredType element = new RecoveredType(memberTypeDeclaration, this, bracketBalanceValue); + memberTypes[memberTypeCount++] = element; + + /* consider that if the opening brace was not found, it is there */ + if (!foundOpeningBrace){ + foundOpeningBrace = true; + this.bracketBalance++; + } + /* if member type not finished, then member type becomes current */ + if (memberTypeDeclaration.declarationSourceEnd == 0) return element; + return this; +} +/* + * Answer the body end of the corresponding parse node + */ +public int bodyEnd(){ + if (bodyEnd == 0) return typeDeclaration.declarationSourceEnd; + return bodyEnd; +} +public boolean bodyStartsAtHeaderEnd(){ + if (typeDeclaration.superInterfaces == null){ + if (typeDeclaration.superclass == null){ + return typeDeclaration.bodyStart == typeDeclaration.sourceEnd+1; + } else { + return typeDeclaration.bodyStart == typeDeclaration.superclass.sourceEnd+1; + } + } else { + return typeDeclaration.bodyStart + == typeDeclaration.superInterfaces[typeDeclaration.superInterfaces.length-1].sourceEnd+1; + } +} +/* + * Answer the enclosing type node, or null if none + */ +public RecoveredType enclosingType(){ + RecoveredElement current = parent; + while (current != null){ + if (current instanceof RecoveredType){ + return (RecoveredType) current; + } + current = current.parent; + } + return null; +} +public char[] name(){ + return typeDeclaration.name; +} +/* + * Answer the associated parsed structure + */ +public ASTNode parseTree(){ + return typeDeclaration; +} +/* + * Answer the very source end of the corresponding parse node + */ +public int sourceEnd(){ + return this.typeDeclaration.declarationSourceEnd; +} +public String toString(int tab) { + StringBuffer result = new StringBuffer(tabString(tab)); + result.append("Recovered type:\n"); //$NON-NLS-1$ + if ((typeDeclaration.bits & ASTNode.IsAnonymousTypeMASK) != 0) { + result.append(tabString(tab)); + result.append(" "); //$NON-NLS-1$ + } + typeDeclaration.print(tab + 1, result); + if (this.memberTypes != null) { + for (int i = 0; i < this.memberTypeCount; i++) { + result.append("\n"); //$NON-NLS-1$ + result.append(this.memberTypes[i].toString(tab + 1)); + } + } + if (this.fields != null) { + for (int i = 0; i < this.fieldCount; i++) { + result.append("\n"); //$NON-NLS-1$ + result.append(this.fields[i].toString(tab + 1)); + } + } + if (this.methods != null) { + for (int i = 0; i < this.methodCount; i++) { + result.append("\n"); //$NON-NLS-1$ + result.append(this.methods[i].toString(tab + 1)); + } + } + return result.toString(); +} +/* + * Update the bodyStart of the corresponding parse node + */ +public void updateBodyStart(int bodyStart){ + this.foundOpeningBrace = true; + this.typeDeclaration.bodyStart = bodyStart; +} +public Statement updatedStatement(){ + + // ignore closed anonymous type + if ((typeDeclaration.bits & ASTNode.IsAnonymousTypeMASK) != 0 && !this.preserveContent){ + return null; + } + + TypeDeclaration updatedType = this.updatedTypeDeclaration(); + if ((updatedType.bits & ASTNode.IsAnonymousTypeMASK) != 0){ + /* in presence of an anonymous type, we want the full allocation expression */ + return updatedType.allocation; + } + return updatedType; +} +public TypeDeclaration updatedTypeDeclaration(){ + + /* update member types */ + if (memberTypeCount > 0){ + int existingCount = typeDeclaration.memberTypes == null ? 0 : typeDeclaration.memberTypes.length; + TypeDeclaration[] memberTypeDeclarations = new TypeDeclaration[existingCount + memberTypeCount]; + if (existingCount > 0){ + System.arraycopy(typeDeclaration.memberTypes, 0, memberTypeDeclarations, 0, existingCount); + } + // may need to update the declarationSourceEnd of the last type + if (memberTypes[memberTypeCount - 1].typeDeclaration.declarationSourceEnd == 0){ + int bodyEndValue = bodyEnd(); + memberTypes[memberTypeCount - 1].typeDeclaration.declarationSourceEnd = bodyEndValue; + memberTypes[memberTypeCount - 1].typeDeclaration.bodyEnd = bodyEndValue; + } + for (int i = 0; i < memberTypeCount; i++){ + memberTypeDeclarations[existingCount + i] = memberTypes[i].updatedTypeDeclaration(); + } + typeDeclaration.memberTypes = memberTypeDeclarations; + } + /* update fields */ + if (fieldCount > 0){ + int existingCount = typeDeclaration.fields == null ? 0 : typeDeclaration.fields.length; + FieldDeclaration[] fieldDeclarations = new FieldDeclaration[existingCount + fieldCount]; + if (existingCount > 0){ + System.arraycopy(typeDeclaration.fields, 0, fieldDeclarations, 0, existingCount); + } + // may need to update the declarationSourceEnd of the last field + if (fields[fieldCount - 1].fieldDeclaration.declarationSourceEnd == 0){ + int temp = bodyEnd(); + fields[fieldCount - 1].fieldDeclaration.declarationSourceEnd = temp; + fields[fieldCount - 1].fieldDeclaration.declarationEnd = temp; + } + for (int i = 0; i < fieldCount; i++){ + fieldDeclarations[existingCount + i] = fields[i].updatedFieldDeclaration(); + } + typeDeclaration.fields = fieldDeclarations; + } + /* update methods */ + int existingCount = typeDeclaration.methods == null ? 0 : typeDeclaration.methods.length; + boolean hasConstructor = false, hasRecoveredConstructor = false; + int defaultConstructorIndex = -1; + if (methodCount > 0){ + AbstractMethodDeclaration[] methodDeclarations = new AbstractMethodDeclaration[existingCount + methodCount]; + for (int i = 0; i < existingCount; i++){ + AbstractMethodDeclaration m = typeDeclaration.methods[i]; + if (m.isDefaultConstructor()) defaultConstructorIndex = i; + methodDeclarations[i] = m; + } + // may need to update the declarationSourceEnd of the last method + if (methods[methodCount - 1].methodDeclaration.declarationSourceEnd == 0){ + int bodyEndValue = bodyEnd(); + methods[methodCount - 1].methodDeclaration.declarationSourceEnd = bodyEndValue; + methods[methodCount - 1].methodDeclaration.bodyEnd = bodyEndValue; + } + for (int i = 0; i < methodCount; i++){ + AbstractMethodDeclaration updatedMethod = methods[i].updatedMethodDeclaration(); + if (updatedMethod.isConstructor()) hasRecoveredConstructor = true; + methodDeclarations[existingCount + i] = updatedMethod; + } + typeDeclaration.methods = methodDeclarations; + hasConstructor = typeDeclaration.checkConstructors(this.parser()); + } else { + for (int i = 0; i < existingCount; i++){ + if (typeDeclaration.methods[i].isConstructor()) hasConstructor = true; + } + } + /* add clinit ? */ + if (typeDeclaration.needClassInitMethod()){ + boolean alreadyHasClinit = false; + for (int i = 0; i < existingCount; i++){ + if (typeDeclaration.methods[i].isClinit()){ + alreadyHasClinit = true; + break; + } + } + if (!alreadyHasClinit) typeDeclaration.addClinit(); + } + /* add default constructor ? */ + if (defaultConstructorIndex >= 0 && hasRecoveredConstructor){ + /* should discard previous default construtor */ + AbstractMethodDeclaration[] methodDeclarations = new AbstractMethodDeclaration[typeDeclaration.methods.length - 1]; + if (defaultConstructorIndex != 0){ + System.arraycopy(typeDeclaration.methods, 0, methodDeclarations, 0, defaultConstructorIndex); + } + if (defaultConstructorIndex != typeDeclaration.methods.length-1){ + System.arraycopy( + typeDeclaration.methods, + defaultConstructorIndex+1, + methodDeclarations, + defaultConstructorIndex, + typeDeclaration.methods.length - defaultConstructorIndex - 1); + } + typeDeclaration.methods = methodDeclarations; + } else { + if (!hasConstructor && !typeDeclaration.isInterface()) {// if was already reduced, then constructor + boolean insideFieldInitializer = false; + RecoveredElement parentElement = this.parent; + while (parentElement != null){ + if (parentElement instanceof RecoveredField){ + insideFieldInitializer = true; + break; + } + parentElement = parentElement.parent; + } + typeDeclaration.createsInternalConstructor(!parser().diet || insideFieldInitializer, true); + } + } + if (parent instanceof RecoveredType){ + typeDeclaration.bits |= ASTNode.IsMemberTypeMASK; + } else if (parent instanceof RecoveredMethod){ + typeDeclaration.bits |= ASTNode.IsLocalTypeMASK; + } + return typeDeclaration; +} +/* + * Update the corresponding parse node from parser state which + * is about to disappear because of restarting recovery + */ +public void updateFromParserState(){ + + if(this.bodyStartsAtHeaderEnd()){ + Parser parser = this.parser(); + /* might want to recover implemented interfaces */ + // protection for bugs 15142 + if (parser.listLength > 0 && parser.astLengthPtr > 0){ // awaiting interface type references + int length = parser.astLengthStack[parser.astLengthPtr]; + int astPtr = parser.astPtr - length; + boolean canConsume = astPtr >= 0; + if(canConsume) { + if((!(parser.astStack[astPtr] instanceof TypeDeclaration))) { + canConsume = false; + } + for (int i = 1, max = length + 1; i < max; i++) { + if(!(parser.astStack[astPtr + i ] instanceof TypeReference)) { + canConsume = false; + } + } + } + if(canConsume) { + parser.consumeClassHeaderImplements(); + // will reset typeListLength to zero + // thus this check will only be performed on first errorCheck after class X implements Y,Z, + } + } + } +} +/* + * A closing brace got consumed, might have closed the current element, + * in which case both the currentElement is exited + */ +public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd){ + if ((--bracketBalance <= 0) && (parent != null)){ + this.updateSourceEndIfNecessary(braceStart, braceEnd); + this.bodyEnd = braceStart - 1; + return parent; + } + return this; +} +/* + * An opening brace got consumed, might be the expected opening one of the current element, + * in which case the bodyStart is updated. + */ +public RecoveredElement updateOnOpeningBrace(int braceStart, int braceEnd){ + /* in case the opening brace is not close enough to the signature, ignore it */ + if (bracketBalance == 0){ + /* + if (parser.scanner.searchLineNumber(typeDeclaration.sourceEnd) + != parser.scanner.searchLineNumber(braceEnd)){ + */ + Parser parser = this.parser(); + switch(parser.lastIgnoredToken){ + case -1 : + case TokenNameextends : + case TokenNameimplements : + if (parser.recoveredStaticInitializerStart == 0) break; + default: + this.foundOpeningBrace = true; + bracketBalance = 1; // pretend the brace was already there + } + } + // might be an initializer + if (this.bracketBalance == 1){ + Block block = new Block(0); + Parser parser = this.parser(); + block.sourceStart = parser.scanner.startPosition; + Initializer init; + if (parser.recoveredStaticInitializerStart == 0){ + init = new Initializer(block, AccDefault); + } else { + init = new Initializer(block, AccStatic); + init.declarationSourceStart = parser.recoveredStaticInitializerStart; + } + init.bodyStart = parser.scanner.currentPosition; + return this.add(init, 1); + } + return super.updateOnOpeningBrace(braceStart, braceEnd); +} +public void updateParseTree(){ + this.updatedTypeDeclaration(); +} +/* + * Update the declarationSourceEnd of the corresponding parse node + */ +public void updateSourceEndIfNecessary(int start, int end){ + if (this.typeDeclaration.declarationSourceEnd == 0){ + this.bodyEnd = 0; + this.typeDeclaration.declarationSourceEnd = end; + this.typeDeclaration.bodyEnd = end; + } +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/RecoveredUnit.java b/src/java/org/eclipse/jdt/internal/compiler/parser/RecoveredUnit.java new file mode 100644 index 0000000..61b1f53 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/parser/RecoveredUnit.java @@ -0,0 +1,203 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.parser; + +/** + * Internal field structure for parsing recovery + */ +import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.ASTNode; +import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; +import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; +import org.eclipse.jdt.internal.compiler.ast.ImportReference; +import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; + +public class RecoveredUnit extends RecoveredElement { + + public CompilationUnitDeclaration unitDeclaration; + + public RecoveredImport[] imports; + public int importCount; + public RecoveredType[] types; + public int typeCount; +public RecoveredUnit(CompilationUnitDeclaration unitDeclaration, int bracketBalance, Parser parser){ + super(null, bracketBalance, parser); + this.unitDeclaration = unitDeclaration; +} +/* + * Record a method declaration: should be attached to last type + */ +public RecoveredElement add(AbstractMethodDeclaration methodDeclaration, int bracketBalanceValue) { + + /* attach it to last type - if any */ + if (this.typeCount > 0){ + RecoveredType type = this.types[this.typeCount -1]; + type.bodyEnd = 0; // reset position + type.typeDeclaration.declarationSourceEnd = 0; // reset position + type.typeDeclaration.bodyEnd = 0; + return type.add(methodDeclaration, bracketBalanceValue); + } + return this; // ignore +} +/* + * Record a field declaration: should be attached to last type + */ +public RecoveredElement add(FieldDeclaration fieldDeclaration, int bracketBalanceValue) { + + /* attach it to last type - if any */ + if (this.typeCount > 0){ + RecoveredType type = this.types[this.typeCount -1]; + type.bodyEnd = 0; // reset position + type.typeDeclaration.declarationSourceEnd = 0; // reset position + type.typeDeclaration.bodyEnd = 0; + return type.add(fieldDeclaration, bracketBalanceValue); + } + return this; // ignore +} +public RecoveredElement add(ImportReference importReference, int bracketBalanceValue) { + if (this.imports == null) { + this.imports = new RecoveredImport[5]; + this.importCount = 0; + } else { + if (this.importCount == this.imports.length) { + System.arraycopy( + this.imports, + 0, + (this.imports = new RecoveredImport[2 * this.importCount]), + 0, + this.importCount); + } + } + RecoveredImport element = new RecoveredImport(importReference, this, bracketBalanceValue); + this.imports[this.importCount++] = element; + + /* if import not finished, then import becomes current */ + if (importReference.declarationSourceEnd == 0) return element; + return this; +} +public RecoveredElement add(TypeDeclaration typeDeclaration, int bracketBalanceValue) { + + if ((typeDeclaration.bits & ASTNode.IsAnonymousTypeMASK) != 0){ + if (this.typeCount > 0) { + // add it to the last type + RecoveredType lastType = this.types[this.typeCount-1]; + lastType.bodyEnd = 0; // reopen type + lastType.typeDeclaration.bodyEnd = 0; // reopen type + lastType.typeDeclaration.declarationSourceEnd = 0; // reopen type + lastType.bracketBalance++; // expect one closing brace + return lastType.add(typeDeclaration, bracketBalanceValue); + } + } + if (this.types == null) { + this.types = new RecoveredType[5]; + this.typeCount = 0; + } else { + if (this.typeCount == this.types.length) { + System.arraycopy( + this.types, + 0, + (this.types = new RecoveredType[2 * this.typeCount]), + 0, + this.typeCount); + } + } + RecoveredType element = new RecoveredType(typeDeclaration, this, bracketBalanceValue); + this.types[this.typeCount++] = element; + + /* if type not finished, then type becomes current */ + if (typeDeclaration.declarationSourceEnd == 0) return element; + return this; +} +/* + * Answer the associated parsed structure + */ +public ASTNode parseTree(){ + return this.unitDeclaration; +} +/* + * Answer the very source end of the corresponding parse node + */ +public int sourceEnd(){ + return this.unitDeclaration.sourceEnd; +} +public String toString(int tab) { + StringBuffer result = new StringBuffer(tabString(tab)); + result.append("Recovered unit: [\n"); //$NON-NLS-1$ + this.unitDeclaration.print(tab + 1, result); + result.append(tabString(tab + 1)); + result.append("]"); //$NON-NLS-1$ + if (this.imports != null) { + for (int i = 0; i < this.importCount; i++) { + result.append("\n"); //$NON-NLS-1$ + result.append(this.imports[i].toString(tab + 1)); + } + } + if (this.types != null) { + for (int i = 0; i < this.typeCount; i++) { + result.append("\n"); //$NON-NLS-1$ + result.append(this.types[i].toString(tab + 1)); + } + } + return result.toString(); +} +public CompilationUnitDeclaration updatedCompilationUnitDeclaration(){ + + /* update imports */ + if (this.importCount > 0){ + ImportReference[] importRefences = new ImportReference[this.importCount]; + for (int i = 0; i < this.importCount; i++){ + importRefences[i] = this.imports[i].updatedImportReference(); + } + this.unitDeclaration.imports = importRefences; + } + /* update types */ + if (this.typeCount > 0){ + int existingCount = this.unitDeclaration.types == null ? 0 : this.unitDeclaration.types.length; + TypeDeclaration[] typeDeclarations = new TypeDeclaration[existingCount + this.typeCount]; + if (existingCount > 0){ + System.arraycopy(this.unitDeclaration.types, 0, typeDeclarations, 0, existingCount); + } + // may need to update the declarationSourceEnd of the last type + if (this.types[this.typeCount - 1].typeDeclaration.declarationSourceEnd == 0){ + this.types[this.typeCount - 1].typeDeclaration.declarationSourceEnd = this.unitDeclaration.sourceEnd; + this.types[this.typeCount - 1].typeDeclaration.bodyEnd = this.unitDeclaration.sourceEnd; + } + int actualCount = existingCount; + for (int i = 0; i < this.typeCount; i++){ + TypeDeclaration typeDecl = this.types[i].updatedTypeDeclaration(); + // filter out local types (12454) + if ((typeDecl.bits & ASTNode.IsLocalTypeMASK) == 0){ + typeDeclarations[actualCount++] = typeDecl; + } + } + if (actualCount != this.typeCount){ + System.arraycopy( + typeDeclarations, + 0, + typeDeclarations = new TypeDeclaration[existingCount+actualCount], + 0, + existingCount+actualCount); + } + this.unitDeclaration.types = typeDeclarations; + } + return this.unitDeclaration; +} +public void updateParseTree(){ + this.updatedCompilationUnitDeclaration(); +} +/* + * Update the sourceEnd of the corresponding parse node + */ +public void updateSourceEndIfNecessary(int bodyStart, int bodyEnd){ + if (this.unitDeclaration.sourceEnd == 0) + this.unitDeclaration.sourceEnd = bodyEnd; +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/Scanner.java b/src/java/org/eclipse/jdt/internal/compiler/parser/Scanner.java new file mode 100644 index 0000000..70e8242 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/parser/Scanner.java @@ -0,0 +1,3432 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.parser; + +import java.util.Iterator; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.core.compiler.InvalidInputException; +import org.eclipse.jdt.internal.compiler.ast.StringLiteral; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; + +/** + * IMPORTANT NOTE: Internal Scanner implementation. It is mirrored in + * org.eclipse.jdt.core.compiler public package where it is API. + * The mirror implementation is using the backward compatible ITerminalSymbols constant + * definitions (stable with 2.0), whereas the internal implementation uses TerminalTokens + * which constant values reflect the latest parser generation state. + */ +public class Scanner implements TerminalTokens { + + /* APIs ares + - getNextToken() which return the current type of the token + (this value is not memorized by the scanner) + - getCurrentTokenSource() which provides with the token "REAL" source + (aka all unicode have been transformed into a correct char) + - sourceStart gives the position into the stream + - currentPosition-1 gives the sourceEnd position into the stream + */ + + // 1.4 feature + private boolean assertMode = false; + public boolean useAssertAsAnIndentifier = false; + //flag indicating if processed source contains occurrences of keyword assert + public boolean containsAssertKeyword = false; + + public boolean recordLineSeparator = false; + public char currentCharacter; + public int startPosition; + public int currentPosition; + public int initialPosition, eofPosition; + // after this position eof are generated instead of real token from the source + + public boolean tokenizeComments = false; + public boolean tokenizeWhiteSpace = false; + + //source should be viewed as a window (aka a part) + //of a entire very large stream + public char source[]; + + //unicode support + public char[] withoutUnicodeBuffer; + public int withoutUnicodePtr; //when == 0 ==> no unicode in the current token + public boolean unicodeAsBackSlash = false; + + public boolean scanningFloatLiteral = false; + + //support for /** comments + public int[] commentStops = new int[10]; + public int[] commentStarts = new int[10]; + public int commentPtr = -1; // no comment test with commentPtr value -1 + protected int lastCommentLinePosition = -1; + + // task tag support + public char[][] foundTaskTags = null; + public char[][] foundTaskMessages; + public char[][] foundTaskPriorities = null; + public int[][] foundTaskPositions; + public int foundTaskCount = 0; + public char[][] taskTags = null; + public char[][] taskPriorities = null; + public boolean isTaskCaseSensitive = true; + + //diet parsing support - jump over some method body when requested + public boolean diet = false; + + //support for the poor-line-debuggers .... + //remember the position of the cr/lf + public int[] lineEnds = new int[250]; + public int linePtr = -1; + public boolean wasAcr = false; + + public static final String END_OF_SOURCE = "End_Of_Source"; //$NON-NLS-1$ + + public static final String INVALID_HEXA = "Invalid_Hexa_Literal"; //$NON-NLS-1$ + public static final String INVALID_OCTAL = "Invalid_Octal_Literal"; //$NON-NLS-1$ + public static final String INVALID_CHARACTER_CONSTANT = "Invalid_Character_Constant"; //$NON-NLS-1$ + public static final String INVALID_ESCAPE = "Invalid_Escape"; //$NON-NLS-1$ + public static final String INVALID_INPUT = "Invalid_Input"; //$NON-NLS-1$ + public static final String INVALID_UNICODE_ESCAPE = "Invalid_Unicode_Escape"; //$NON-NLS-1$ + public static final String INVALID_FLOAT = "Invalid_Float_Literal"; //$NON-NLS-1$ + + public static final String NULL_SOURCE_STRING = "Null_Source_String"; //$NON-NLS-1$ + public static final String UNTERMINATED_STRING = "Unterminated_String"; //$NON-NLS-1$ + public static final String UNTERMINATED_COMMENT = "Unterminated_Comment"; //$NON-NLS-1$ + public static final String INVALID_CHAR_IN_STRING = "Invalid_Char_In_String"; //$NON-NLS-1$ + + //----------------optimized identifier managment------------------ + static final char[] charArray_a = new char[] {'a'}, + charArray_b = new char[] {'b'}, + charArray_c = new char[] {'c'}, + charArray_d = new char[] {'d'}, + charArray_e = new char[] {'e'}, + charArray_f = new char[] {'f'}, + charArray_g = new char[] {'g'}, + charArray_h = new char[] {'h'}, + charArray_i = new char[] {'i'}, + charArray_j = new char[] {'j'}, + charArray_k = new char[] {'k'}, + charArray_l = new char[] {'l'}, + charArray_m = new char[] {'m'}, + charArray_n = new char[] {'n'}, + charArray_o = new char[] {'o'}, + charArray_p = new char[] {'p'}, + charArray_q = new char[] {'q'}, + charArray_r = new char[] {'r'}, + charArray_s = new char[] {'s'}, + charArray_t = new char[] {'t'}, + charArray_u = new char[] {'u'}, + charArray_v = new char[] {'v'}, + charArray_w = new char[] {'w'}, + charArray_x = new char[] {'x'}, + charArray_y = new char[] {'y'}, + charArray_z = new char[] {'z'}; + + static final char[] initCharArray = + new char[] {'\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000'}; + static final int TableSize = 30, InternalTableSize = 6; //30*6 = 180 entries + public static final int OptimizedLength = 6; + public /*static*/ final char[][][][] charArray_length = + new char[OptimizedLength][TableSize][InternalTableSize][]; + // support for detecting non-externalized string literals + NLSLine currentLine= null; + public static final String TAG_PREFIX= "//$NON-NLS-"; //$NON-NLS-1$ + public static final int TAG_PREFIX_LENGTH= TAG_PREFIX.length(); + public static final String TAG_POSTFIX= "$"; //$NON-NLS-1$ + public static final int TAG_POSTFIX_LENGTH= TAG_POSTFIX.length(); + public StringLiteral[] nonNLSStrings = null; + public boolean checkNonExternalizedStringLiterals = false; + public boolean wasNonExternalizedStringLiteral = false; + + /*static*/ { + for (int i = 0; i < 6; i++) { + for (int j = 0; j < TableSize; j++) { + for (int k = 0; k < InternalTableSize; k++) { + this.charArray_length[i][j][k] = initCharArray; + } + } + } + } + static int newEntry2 = 0, + newEntry3 = 0, + newEntry4 = 0, + newEntry5 = 0, + newEntry6 = 0; + + public static final int RoundBracket = 0; + public static final int SquareBracket = 1; + public static final int CurlyBracket = 2; + public static final int BracketKinds = 3; + +public Scanner() { + this(false /*comment*/, false /*whitespace*/, false /*nls*/, ClassFileConstants.JDK1_3 /*sourceLevel*/, null/*taskTag*/, null/*taskPriorities*/, true /*taskCaseSensitive*/); +} + +public Scanner( + boolean tokenizeComments, + boolean tokenizeWhiteSpace, + boolean checkNonExternalizedStringLiterals, + long sourceLevel, + char[][] taskTags, + char[][] taskPriorities, + boolean isTaskCaseSensitive) { + + this.eofPosition = Integer.MAX_VALUE; + this.tokenizeComments = tokenizeComments; + this.tokenizeWhiteSpace = tokenizeWhiteSpace; + this.checkNonExternalizedStringLiterals = checkNonExternalizedStringLiterals; + this.assertMode = sourceLevel >= ClassFileConstants.JDK1_4; + this.taskTags = taskTags; + this.taskPriorities = taskPriorities; + this.isTaskCaseSensitive = isTaskCaseSensitive; +} + +public final boolean atEnd() { + // This code is not relevant if source is + // Only a part of the real stream input + + return this.source.length == this.currentPosition; +} + +private void checkNonExternalizedString() { + if (this.currentLine == null) + return; + parseTags(this.currentLine); +} + +// chech presence of task: tags +// TODO (frederic) see if we need to take unicode characters into account... +public void checkTaskTag(int commentStart, int commentEnd) { + char[] src = this.source; + + // only look for newer task: tags + if (this.foundTaskCount > 0 + && this.foundTaskPositions[this.foundTaskCount - 1][0] >= commentStart) { + return; + } + int foundTaskIndex = this.foundTaskCount; + char previous = src[commentStart+1]; // should be '*' or '/' + nextChar : for ( + int i = commentStart + 2; i < commentEnd && i < this.eofPosition; i++) { + char[] tag = null; + char[] priority = null; + // check for tag occurrence only if not ambiguous with javadoc tag + if (previous != '@') { + nextTag : for (int itag = 0; itag < this.taskTags.length; itag++) { + tag = this.taskTags[itag]; + int tagLength = tag.length; + if (tagLength == 0) continue nextTag; + + // ensure tag is not leaded with letter if tag starts with a letter + if (Character.isJavaIdentifierStart(tag[0])) { + if (Character.isJavaIdentifierPart(previous)) { + continue nextTag; + } + } + + for (int t = 0; t < tagLength; t++) { + char sc, tc; + int x = i+t; + if (x >= this.eofPosition || x >= commentEnd) continue nextTag; + if ((sc = src[i + t]) != (tc = tag[t])) { // case sensitive check + if (this.isTaskCaseSensitive || (Character.toLowerCase(sc) != Character.toLowerCase(tc))) { // case insensitive check + continue nextTag; + } + } + } + // ensure tag is not followed with letter if tag finishes with a letter + if (i+tagLength < commentEnd && Character.isJavaIdentifierPart(src[i+tagLength-1])) { + if (Character.isJavaIdentifierPart(src[i + tagLength])) + continue nextTag; + } + if (this.foundTaskTags == null) { + this.foundTaskTags = new char[5][]; + this.foundTaskMessages = new char[5][]; + this.foundTaskPriorities = new char[5][]; + this.foundTaskPositions = new int[5][]; + } else if (this.foundTaskCount == this.foundTaskTags.length) { + System.arraycopy(this.foundTaskTags, 0, this.foundTaskTags = new char[this.foundTaskCount * 2][], 0, this.foundTaskCount); + System.arraycopy(this.foundTaskMessages, 0, this.foundTaskMessages = new char[this.foundTaskCount * 2][], 0, this.foundTaskCount); + System.arraycopy(this.foundTaskPriorities, 0, this.foundTaskPriorities = new char[this.foundTaskCount * 2][], 0, this.foundTaskCount); + System.arraycopy(this.foundTaskPositions, 0, this.foundTaskPositions = new int[this.foundTaskCount * 2][], 0, this.foundTaskCount); + } + + priority = this.taskPriorities != null && itag < this.taskPriorities.length + ? this.taskPriorities[itag] + : null; + + this.foundTaskTags[this.foundTaskCount] = tag; + this.foundTaskPriorities[this.foundTaskCount] = priority; + this.foundTaskPositions[this.foundTaskCount] = new int[] { i, i + tagLength - 1 }; + this.foundTaskMessages[this.foundTaskCount] = CharOperation.NO_CHAR; + this.foundTaskCount++; + i += tagLength - 1; // will be incremented when looping + break nextTag; + } + } + previous = src[i]; + } + for (int i = foundTaskIndex; i < this.foundTaskCount; i++) { + // retrieve message start and end positions + int msgStart = this.foundTaskPositions[i][0] + this.foundTaskTags[i].length; + int max_value = i + 1 < this.foundTaskCount + ? this.foundTaskPositions[i + 1][0] - 1 + : commentEnd - 1; + // at most beginning of next task + if (max_value < msgStart) { + max_value = msgStart; // would only occur if tag is before EOF. + } + int end = -1; + char c; + for (int j = msgStart; j < max_value; j++) { + if ((c = src[j]) == '\n' || c == '\r') { + end = j - 1; + break; + } + } + if (end == -1) { + for (int j = max_value; j > msgStart; j--) { + if ((c = src[j]) == '*') { + end = j - 1; + break; + } + } + if (end == -1) + end = max_value; + } + if (msgStart == end) + continue; // empty + // trim the message + while (CharOperation.isWhitespace(src[end]) && msgStart <= end) + end--; + while (CharOperation.isWhitespace(src[msgStart]) && msgStart <= end) + msgStart++; + // update the end position of the task + this.foundTaskPositions[i][1] = end; + // get the message source + final int messageLength = end - msgStart + 1; + char[] message = new char[messageLength]; + System.arraycopy(src, msgStart, message, 0, messageLength); + this.foundTaskMessages[i] = message; + } +} +public char[] getCurrentIdentifierSource() { + //return the token REAL source (aka unicodes are precomputed) + + char[] result; + if (this.withoutUnicodePtr != 0) { + //0 is used as a fast test flag so the real first char is in position 1 + System.arraycopy( + this.withoutUnicodeBuffer, + 1, + result = new char[this.withoutUnicodePtr], + 0, + this.withoutUnicodePtr); + } else { + int length = this.currentPosition - this.startPosition; + if (length == this.source.length) return this.source; + switch (length) { // see OptimizedLength + case 1 : + return optimizedCurrentTokenSource1(); + case 2 : + return optimizedCurrentTokenSource2(); + case 3 : + return optimizedCurrentTokenSource3(); + case 4 : + return optimizedCurrentTokenSource4(); + case 5 : + return optimizedCurrentTokenSource5(); + case 6 : + return optimizedCurrentTokenSource6(); + } + //no optimization + System.arraycopy(this.source, this.startPosition, result = new char[length], 0, length); + } + return result; +} +public int getCurrentTokenEndPosition(){ + return this.currentPosition - 1; +} +public final char[] getCurrentTokenSource() { + // Return the token REAL source (aka unicodes are precomputed) + + char[] result; + if (this.withoutUnicodePtr != 0) + // 0 is used as a fast test flag so the real first char is in position 1 + System.arraycopy( + this.withoutUnicodeBuffer, + 1, + result = new char[this.withoutUnicodePtr], + 0, + this.withoutUnicodePtr); + else { + int length; + System.arraycopy( + this.source, + this.startPosition, + result = new char[length = this.currentPosition - this.startPosition], + 0, + length); + } + return result; +} +public final char[] getCurrentTokenSourceString() { + //return the token REAL source (aka unicodes are precomputed). + //REMOVE the two " that are at the beginning and the end. + + char[] result; + if (this.withoutUnicodePtr != 0) + //0 is used as a fast test flag so the real first char is in position 1 + System.arraycopy(this.withoutUnicodeBuffer, 2, + //2 is 1 (real start) + 1 (to jump over the ") + result = new char[this.withoutUnicodePtr - 2], 0, this.withoutUnicodePtr - 2); + else { + int length; + System.arraycopy( + this.source, + this.startPosition + 1, + result = new char[length = this.currentPosition - this.startPosition - 2], + 0, + length); + } + return result; +} + +public final char[] getRawTokenSource() { + int length = this.currentPosition - this.startPosition; + char[] tokenSource = new char[length]; + System.arraycopy(this.source, this.startPosition, tokenSource, 0, length); + return tokenSource; +} + +public final char[] getRawTokenSourceEnd() { + int length = this.eofPosition - this.currentPosition - 1; + char[] sourceEnd = new char[length]; + System.arraycopy(this.source, this.currentPosition, sourceEnd, 0, length); + return sourceEnd; +} + +public int getCurrentTokenStartPosition(){ + return this.startPosition; +} +/* + * Search the source position corresponding to the end of a given line number + * + * Line numbers are 1-based, and relative to the scanner initialPosition. + * Character positions are 0-based. + * + * In case the given line number is inconsistent, answers -1. + */ +public final int getLineEnd(int lineNumber) { + + if (this.lineEnds == null) + return -1; + if (lineNumber > this.lineEnds.length+1) + return -1; + if (lineNumber <= 0) + return -1; + if (lineNumber == this.lineEnds.length + 1) + return this.eofPosition; + return this.lineEnds[lineNumber-1]; // next line start one character behind the lineEnd of the previous line +} + +public final int[] getLineEnds() { + //return a bounded copy of this.lineEnds + + int[] copy; + System.arraycopy(this.lineEnds, 0, copy = new int[this.linePtr + 1], 0, this.linePtr + 1); + return copy; +} + +/** + * Search the source position corresponding to the beginning of a given line number + * + * Line numbers are 1-based, and relative to the scanner initialPosition. + * Character positions are 0-based. + * + * e.g. getLineStart(1) --> 0 indicates that the first line starts at character 0. + * + * In case the given line number is inconsistent, answers -1. + * + * @param lineNumber int + * @return int + */ +public final int getLineStart(int lineNumber) { + + if (this.lineEnds == null) + return -1; + if (lineNumber > this.lineEnds.length + 1) + return -1; + if (lineNumber <= 0) + return -1; + + if (lineNumber == 1) + return this.initialPosition; + return this.lineEnds[lineNumber-2]+1; // next line start one character behind the lineEnd of the previous line +} +public final int getNextChar() { + try { + if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') + && (this.source[this.currentPosition] == 'u')) { + //-------------unicode traitement ------------ + int c1, c2, c3, c4; + int unicodeSize = 6; + this.currentPosition++; + while (this.source[this.currentPosition] == 'u') { + this.currentPosition++; + unicodeSize++; + } + + if (((c1 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 + || c1 < 0) + || ((c2 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c2 < 0) + || ((c3 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c3 < 0) + || ((c4 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c4 < 0)) { + return -1; + } + + this.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + + this.unicodeAsBackSlash = this.currentCharacter == '\\'; + + //need the unicode buffer + if (this.withoutUnicodePtr == 0) { + //buffer all the entries that have been left aside.... + unicodeInitializeBuffer(this.currentPosition - unicodeSize - this.startPosition); + } + //fill the buffer with the char + unicodeStoreAt(++this.withoutUnicodePtr); + return this.currentCharacter; + + } //-------------end unicode traitement-------------- + else { + this.unicodeAsBackSlash = false; + if (this.withoutUnicodePtr != 0) { + unicodeStoreAt(++this.withoutUnicodePtr); + } + return this.currentCharacter; + } + } catch (IndexOutOfBoundsException e) { + return -1; + } +} +public final boolean getNextChar(char testedChar) { + //BOOLEAN + //handle the case of unicode. + //when a unicode appears then we must use a buffer that holds char internal values + //At the end of this method currentCharacter holds the new visited char + //and currentPosition points right next after it + //Both previous lines are true if the currentCharacter is == to the testedChar + //On false, no side effect has occured. + + //ALL getNextChar.... ARE OPTIMIZED COPIES + + if (this.currentPosition >= this.source.length) { // handle the obvious case upfront + this.unicodeAsBackSlash = false; + return false; + } + + int temp = this.currentPosition; + try { + if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') + && (this.source[this.currentPosition] == 'u')) { + //-------------unicode traitement ------------ + int c1, c2, c3, c4; + int unicodeSize = 6; + this.currentPosition++; + while (this.source[this.currentPosition] == 'u') { + this.currentPosition++; + unicodeSize++; + } + + if (((c1 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 + || c1 < 0) + || ((c2 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c2 < 0) + || ((c3 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c3 < 0) + || ((c4 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c4 < 0)) { + this.currentPosition = temp; + return false; + } + + this.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + if (this.currentCharacter != testedChar) { + this.currentPosition = temp; + return false; + } + this.unicodeAsBackSlash = this.currentCharacter == '\\'; + + //need the unicode buffer + if (this.withoutUnicodePtr == 0) { + //buffer all the entries that have been left aside.... + unicodeInitializeBuffer(this.currentPosition - unicodeSize - this.startPosition); + } + //fill the buffer with the char + unicodeStoreAt(++this.withoutUnicodePtr); + return true; + + } //-------------end unicode traitement-------------- + else { + if (this.currentCharacter != testedChar) { + this.currentPosition = temp; + return false; + } + this.unicodeAsBackSlash = false; + if (this.withoutUnicodePtr != 0) + unicodeStoreAt(++this.withoutUnicodePtr); + return true; + } + } catch (IndexOutOfBoundsException e) { + this.unicodeAsBackSlash = false; + this.currentPosition = temp; + return false; + } +} +public final int getNextChar(char testedChar1, char testedChar2) { + //INT 0 : testChar1 \\\\///\\\\ 1 : testedChar2 \\\\///\\\\ -1 : others + //test can be done with (x==0) for the first and (x>0) for the second + //handle the case of unicode. + //when a unicode appears then we must use a buffer that holds char internal values + //At the end of this method currentCharacter holds the new visited char + //and currentPosition points right next after it + //Both previous lines are true if the currentCharacter is == to the testedChar1/2 + //On false, no side effect has occured. + + //ALL getNextChar.... ARE OPTIMIZED COPIES + if (this.currentPosition >= this.source.length) // handle the obvious case upfront + return -1; + + int temp = this.currentPosition; + try { + int result; + if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') + && (this.source[this.currentPosition] == 'u')) { + //-------------unicode traitement ------------ + int c1, c2, c3, c4; + int unicodeSize = 6; + this.currentPosition++; + while (this.source[this.currentPosition] == 'u') { + this.currentPosition++; + unicodeSize++; + } + + if (((c1 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 + || c1 < 0) + || ((c2 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c2 < 0) + || ((c3 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c3 < 0) + || ((c4 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c4 < 0)) { + this.currentPosition = temp; + return 2; + } + + this.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + if (this.currentCharacter == testedChar1) + result = 0; + else + if (this.currentCharacter == testedChar2) + result = 1; + else { + this.currentPosition = temp; + return -1; + } + + //need the unicode buffer + if (this.withoutUnicodePtr == 0) { + //buffer all the entries that have been left aside.... + unicodeInitializeBuffer(this.currentPosition - unicodeSize - this.startPosition); + } + //fill the buffer with the char + unicodeStoreAt(++this.withoutUnicodePtr); + return result; + } //-------------end unicode traitement-------------- + else { + if (this.currentCharacter == testedChar1) + result = 0; + else + if (this.currentCharacter == testedChar2) + result = 1; + else { + this.currentPosition = temp; + return -1; + } + + if (this.withoutUnicodePtr != 0) + unicodeStoreAt(++this.withoutUnicodePtr); + return result; + } + } catch (IndexOutOfBoundsException e) { + this.currentPosition = temp; + return -1; + } +} +public final boolean getNextCharAsDigit() throws InvalidInputException { + //BOOLEAN + //handle the case of unicode. + //when a unicode appears then we must use a buffer that holds char internal values + //At the end of this method currentCharacter holds the new visited char + //and currentPosition points right next after it + //Both previous lines are true if the currentCharacter is a digit + //On false, no side effect has occured. + + //ALL getNextChar.... ARE OPTIMIZED COPIES + if (this.currentPosition >= this.source.length) // handle the obvious case upfront + return false; + + int temp = this.currentPosition; + try { + if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') + && (this.source[this.currentPosition] == 'u')) { + //-------------unicode traitement ------------ + int c1, c2, c3, c4; + int unicodeSize = 6; + this.currentPosition++; + while (this.source[this.currentPosition] == 'u') { + this.currentPosition++; + unicodeSize++; + } + + if (((c1 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 + || c1 < 0) + || ((c2 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c2 < 0) + || ((c3 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c3 < 0) + || ((c4 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c4 < 0)) { + this.currentPosition = temp; + return false; + } + + this.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + if (!isDigit(this.currentCharacter)) { + this.currentPosition = temp; + return false; + } + + //need the unicode buffer + if (this.withoutUnicodePtr == 0) { + //buffer all the entries that have been left aside.... + unicodeInitializeBuffer(this.currentPosition - unicodeSize - this.startPosition); + } + //fill the buffer with the char + unicodeStoreAt(++this.withoutUnicodePtr); + return true; + } //-------------end unicode traitement-------------- + else { + if (!isDigit(this.currentCharacter)) { + this.currentPosition = temp; + return false; + } + if (this.withoutUnicodePtr != 0) + unicodeStoreAt(++this.withoutUnicodePtr); + return true; + } + } catch (IndexOutOfBoundsException e) { + this.currentPosition = temp; + return false; + } +} +public final boolean getNextCharAsDigit(int radix) { + //BOOLEAN + //handle the case of unicode. + //when a unicode appears then we must use a buffer that holds char internal values + //At the end of this method currentCharacter holds the new visited char + //and currentPosition points right next after it + //Both previous lines are true if the currentCharacter is a digit base on radix + //On false, no side effect has occured. + + //ALL getNextChar.... ARE OPTIMIZED COPIES + if (this.currentPosition >= this.source.length) // handle the obvious case upfront + return false; + + int temp = this.currentPosition; + try { + if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') + && (this.source[this.currentPosition] == 'u')) { + //-------------unicode traitement ------------ + int c1, c2, c3, c4; + int unicodeSize = 6; + this.currentPosition++; + while (this.source[this.currentPosition] == 'u') { + this.currentPosition++; + unicodeSize++; + } + + if (((c1 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 + || c1 < 0) + || ((c2 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c2 < 0) + || ((c3 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c3 < 0) + || ((c4 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c4 < 0)) { + this.currentPosition = temp; + return false; + } + + this.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + if (Character.digit(this.currentCharacter, radix) == -1) { + this.currentPosition = temp; + return false; + } + + //need the unicode buffer + if (this.withoutUnicodePtr == 0) { + //buffer all the entries that have been left aside.... + unicodeInitializeBuffer(this.currentPosition - unicodeSize - this.startPosition); + } + //fill the buffer with the char + unicodeStoreAt(++this.withoutUnicodePtr); + return true; + } //-------------end unicode traitement-------------- + else { + if (Character.digit(this.currentCharacter, radix) == -1) { + this.currentPosition = temp; + return false; + } + if (this.withoutUnicodePtr != 0) + unicodeStoreAt(++this.withoutUnicodePtr); + return true; + } + } catch (IndexOutOfBoundsException e) { + this.currentPosition = temp; + return false; + } +} +public boolean getNextCharAsJavaIdentifierPart() { + //BOOLEAN + //handle the case of unicode. + //when a unicode appears then we must use a buffer that holds char internal values + //At the end of this method currentCharacter holds the new visited char + //and currentPosition points right next after it + //Both previous lines are true if the currentCharacter is a JavaIdentifierPart + //On false, no side effect has occured. + + //ALL getNextChar.... ARE OPTIMIZED COPIES + if (this.currentPosition >= this.source.length) // handle the obvious case upfront + return false; + + int temp = this.currentPosition; + try { + if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') + && (this.source[this.currentPosition] == 'u')) { + //-------------unicode traitement ------------ + int c1, c2, c3, c4; + int unicodeSize = 6; + this.currentPosition++; + while (this.source[this.currentPosition] == 'u') { + this.currentPosition++; + unicodeSize++; + } + + if (((c1 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 + || c1 < 0) + || ((c2 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c2 < 0) + || ((c3 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c3 < 0) + || ((c4 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c4 < 0)) { + this.currentPosition = temp; + return false; + } + + this.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + if (!Character.isJavaIdentifierPart(this.currentCharacter)) { + this.currentPosition = temp; + return false; + } + + //need the unicode buffer + if (this.withoutUnicodePtr == 0) { + //buffer all the entries that have been left aside.... + unicodeInitializeBuffer(this.currentPosition - unicodeSize - this.startPosition); + } + //fill the buffer with the char + unicodeStoreAt(++this.withoutUnicodePtr); + return true; + } //-------------end unicode traitement-------------- + else { + if (!Character.isJavaIdentifierPart(this.currentCharacter)) { + this.currentPosition = temp; + return false; + } + + if (this.withoutUnicodePtr != 0) + unicodeStoreAt(++this.withoutUnicodePtr); + return true; + } + } catch (IndexOutOfBoundsException e) { + this.currentPosition = temp; + return false; + } +} +public int getNextToken() throws InvalidInputException { + this.wasAcr = false; + if (this.diet) { + jumpOverMethodBody(); + this.diet = false; + return this.currentPosition > this.source.length ? TokenNameEOF : TokenNameRBRACE; + } + int whiteStart = 0; + try { + while (true) { //loop for jumping over comments + this.withoutUnicodePtr = 0; + //start with a new token (even comment written with unicode ) + + // ---------Consume white space and handles startPosition--------- + whiteStart = this.currentPosition; + boolean isWhiteSpace, hasWhiteSpaces = false; + int offset = 0; + do { + this.startPosition = this.currentPosition; + boolean checkIfUnicode = false; + try { + checkIfUnicode = ((this.currentCharacter = this.source[this.currentPosition++]) == '\\') + && (this.source[this.currentPosition] == 'u'); + } catch(IndexOutOfBoundsException e) { + if (this.tokenizeWhiteSpace && (whiteStart != this.currentPosition - 1)) { + // reposition scanner in case we are interested by spaces as tokens + this.currentPosition--; + this.startPosition = whiteStart; + return TokenNameWHITESPACE; + } + if (this.currentPosition > this.eofPosition) + return TokenNameEOF; + } + if (checkIfUnicode) { + isWhiteSpace = jumpOverUnicodeWhiteSpace(); + offset = 6; + } else { + offset = 1; + if ((this.currentCharacter == '\r') || (this.currentCharacter == '\n')) { + checkNonExternalizedString(); + if (this.recordLineSeparator) { + pushLineSeparator(); + } else { + this.currentLine = null; + } + } + isWhiteSpace = + (this.currentCharacter == ' ') || CharOperation.isWhitespace(this.currentCharacter); + } + if (isWhiteSpace) { + hasWhiteSpaces = true; + } + } while (isWhiteSpace); + if (this.tokenizeWhiteSpace && hasWhiteSpaces) { + // reposition scanner in case we are interested by spaces as tokens + this.currentPosition-=offset; + this.startPosition = whiteStart; + return TokenNameWHITESPACE; + } + //little trick to get out in the middle of a source compuation + if (this.currentPosition > this.eofPosition) + return TokenNameEOF; + + // ---------Identify the next token------------- + + switch (this.currentCharacter) { + case '(' : + return TokenNameLPAREN; + case ')' : + return TokenNameRPAREN; + case '{' : + return TokenNameLBRACE; + case '}' : + return TokenNameRBRACE; + case '[' : + return TokenNameLBRACKET; + case ']' : + return TokenNameRBRACKET; + case ';' : + return TokenNameSEMICOLON; + case ',' : + return TokenNameCOMMA; + case '.' : + if (getNextCharAsDigit()) + return scanNumber(true); + return TokenNameDOT; + case '+' : + { + int test; + if ((test = getNextChar('+', '=')) == 0) + return TokenNamePLUS_PLUS; + if (test > 0) + return TokenNamePLUS_EQUAL; + return TokenNamePLUS; + } + case '-' : + { + int test; + if ((test = getNextChar('-', '=')) == 0) + return TokenNameMINUS_MINUS; + if (test > 0) + return TokenNameMINUS_EQUAL; + return TokenNameMINUS; + } + case '~' : + return TokenNameTWIDDLE; + case '!' : + if (getNextChar('=')) + return TokenNameNOT_EQUAL; + return TokenNameNOT; + case '*' : + if (getNextChar('=')) + return TokenNameMULTIPLY_EQUAL; + return TokenNameMULTIPLY; + case '%' : + if (getNextChar('=')) + return TokenNameREMAINDER_EQUAL; + return TokenNameREMAINDER; + case '<' : + { + int test; + if ((test = getNextChar('=', '<')) == 0) + return TokenNameLESS_EQUAL; + if (test > 0) { + if (getNextChar('=')) + return TokenNameLEFT_SHIFT_EQUAL; + return TokenNameLEFT_SHIFT; + } + return TokenNameLESS; + } + case '>' : + { + int test; + if ((test = getNextChar('=', '>')) == 0) + return TokenNameGREATER_EQUAL; + if (test > 0) { + if ((test = getNextChar('=', '>')) == 0) + return TokenNameRIGHT_SHIFT_EQUAL; + if (test > 0) { + if (getNextChar('=')) + return TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL; + return TokenNameUNSIGNED_RIGHT_SHIFT; + } + return TokenNameRIGHT_SHIFT; + } + return TokenNameGREATER; + } + case '=' : + if (getNextChar('=')) + return TokenNameEQUAL_EQUAL; + return TokenNameEQUAL; + case '&' : + { + int test; + if ((test = getNextChar('&', '=')) == 0) + return TokenNameAND_AND; + if (test > 0) + return TokenNameAND_EQUAL; + return TokenNameAND; + } + case '|' : + { + int test; + if ((test = getNextChar('|', '=')) == 0) + return TokenNameOR_OR; + if (test > 0) + return TokenNameOR_EQUAL; + return TokenNameOR; + } + case '^' : + if (getNextChar('=')) + return TokenNameXOR_EQUAL; + return TokenNameXOR; + case '?' : + return TokenNameQUESTION; + case ':' : + return TokenNameCOLON; + case '\'' : + { + int test; + if ((test = getNextChar('\n', '\r')) == 0) { + throw new InvalidInputException(INVALID_CHARACTER_CONSTANT); + } + if (test > 0) { + // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed + for (int lookAhead = 0; lookAhead < 3; lookAhead++) { + if (this.currentPosition + lookAhead == this.source.length) + break; + if (this.source[this.currentPosition + lookAhead] == '\n') + break; + if (this.source[this.currentPosition + lookAhead] == '\'') { + this.currentPosition += lookAhead + 1; + break; + } + } + throw new InvalidInputException(INVALID_CHARACTER_CONSTANT); + } + } + if (getNextChar('\'')) { + // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed + for (int lookAhead = 0; lookAhead < 3; lookAhead++) { + if (this.currentPosition + lookAhead == this.source.length) + break; + if (this.source[this.currentPosition + lookAhead] == '\n') + break; + if (this.source[this.currentPosition + lookAhead] == '\'') { + this.currentPosition += lookAhead + 1; + break; + } + } + throw new InvalidInputException(INVALID_CHARACTER_CONSTANT); + } + if (getNextChar('\\')) + scanEscapeCharacter(); + else { // consume next character + this.unicodeAsBackSlash = false; + boolean checkIfUnicode = false; + try { + checkIfUnicode = ((this.currentCharacter = this.source[this.currentPosition++]) == '\\') + && (this.source[this.currentPosition] == 'u'); + } catch(IndexOutOfBoundsException e) { + this.currentPosition--; + throw new InvalidInputException(INVALID_CHARACTER_CONSTANT); + } + if (checkIfUnicode) { + getNextUnicodeChar(); + } else { + if (this.withoutUnicodePtr != 0) { + unicodeStoreAt(++this.withoutUnicodePtr); + } + } + } + if (getNextChar('\'')) + return TokenNameCharacterLiteral; + // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed + for (int lookAhead = 0; lookAhead < 20; lookAhead++) { + if (this.currentPosition + lookAhead == this.source.length) + break; + if (this.source[this.currentPosition + lookAhead] == '\n') + break; + if (this.source[this.currentPosition + lookAhead] == '\'') { + this.currentPosition += lookAhead + 1; + break; + } + } + throw new InvalidInputException(INVALID_CHARACTER_CONSTANT); + case '"' : + try { + // consume next character + this.unicodeAsBackSlash = false; + boolean isUnicode = false; + if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') + && (this.source[this.currentPosition] == 'u')) { + getNextUnicodeChar(); + isUnicode = true; + } else { + if (this.withoutUnicodePtr != 0) { + unicodeStoreAt(++this.withoutUnicodePtr); + } + } + + while (this.currentCharacter != '"') { + /**** \r and \n are not valid in string literals ****/ + if ((this.currentCharacter == '\n') || (this.currentCharacter == '\r')) { + // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed + if (isUnicode) { + int start = this.currentPosition; + for (int lookAhead = 0; lookAhead < 50; lookAhead++) { + if (this.currentPosition >= this.eofPosition) { + this.currentPosition = start; + break; + } + if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') && (this.source[this.currentPosition] == 'u')) { + isUnicode = true; + getNextUnicodeChar(); + } else { + isUnicode = false; + } + if (!isUnicode && this.currentCharacter == '\n') { + this.currentPosition--; // set current position on new line character + break; + } + if (this.currentCharacter == '\"') { + throw new InvalidInputException(INVALID_CHAR_IN_STRING); + } + } + } else { + this.currentPosition--; // set current position on new line character + } + throw new InvalidInputException(INVALID_CHAR_IN_STRING); + } + if (this.currentCharacter == '\\') { + int escapeSize = this.currentPosition; + boolean backSlashAsUnicodeInString = this.unicodeAsBackSlash; + //scanEscapeCharacter make a side effect on this value and we need the previous value few lines down this one + scanEscapeCharacter(); + escapeSize = this.currentPosition - escapeSize; + if (this.withoutUnicodePtr == 0) { + //buffer all the entries that have been left aside.... + unicodeInitializeBuffer(this.currentPosition - escapeSize - 1 - this.startPosition); + unicodeStoreAt(++this.withoutUnicodePtr); + } else { //overwrite the / in the buffer + unicodeStoreAt(this.withoutUnicodePtr); + if (backSlashAsUnicodeInString) { //there are TWO \ in the stream where only one is correct + this.withoutUnicodePtr--; + } + } + } + // consume next character + this.unicodeAsBackSlash = false; + if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') + && (this.source[this.currentPosition] == 'u')) { + getNextUnicodeChar(); + } else { + if (this.withoutUnicodePtr != 0) { + unicodeStoreAt(++this.withoutUnicodePtr); + } + } + + } + } catch (IndexOutOfBoundsException e) { + this.currentPosition--; + throw new InvalidInputException(UNTERMINATED_STRING); + } catch (InvalidInputException e) { + if (e.getMessage().equals(INVALID_ESCAPE)) { + // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed + for (int lookAhead = 0; lookAhead < 50; lookAhead++) { + if (this.currentPosition + lookAhead == this.source.length) + break; + if (this.source[this.currentPosition + lookAhead] == '\n') + break; + if (this.source[this.currentPosition + lookAhead] == '\"') { + this.currentPosition += lookAhead + 1; + break; + } + } + + } + throw e; // rethrow + } + if (this.checkNonExternalizedStringLiterals){ // check for presence of NLS tags //$NON-NLS-?$ where ? is an int. + if (this.currentLine == null) { + this.currentLine = new NLSLine(); + } + this.currentLine.add( + new StringLiteral( + getCurrentTokenSourceString(), + this.startPosition, + this.currentPosition - 1)); + } + return TokenNameStringLiteral; + case '/' : + { + int test; + if ((test = getNextChar('/', '*')) == 0) { //line comment + this.lastCommentLinePosition = this.currentPosition; + try { //get the next char + if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') + && (this.source[this.currentPosition] == 'u')) { + //-------------unicode traitement ------------ + int c1 = 0, c2 = 0, c3 = 0, c4 = 0; + this.currentPosition++; + while (this.source[this.currentPosition] == 'u') { + this.currentPosition++; + } + if ((c1 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 + || c1 < 0 + || (c2 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 + || c2 < 0 + || (c3 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 + || c3 < 0 + || (c4 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 + || c4 < 0) { + throw new InvalidInputException(INVALID_UNICODE_ESCAPE); + } else { + this.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + } + } + + //handle the \\u case manually into comment + if (this.currentCharacter == '\\') { + if (this.source[this.currentPosition] == '\\') + this.currentPosition++; + } //jump over the \\ + boolean isUnicode = false; + while (this.currentCharacter != '\r' && this.currentCharacter != '\n') { + this.lastCommentLinePosition = this.currentPosition; + //get the next char + isUnicode = false; + if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') + && (this.source[this.currentPosition] == 'u')) { + isUnicode = true; + //-------------unicode traitement ------------ + int c1 = 0, c2 = 0, c3 = 0, c4 = 0; + this.currentPosition++; + while (this.source[this.currentPosition] == 'u') { + this.currentPosition++; + } + if ((c1 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 + || c1 < 0 + || (c2 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 + || c2 < 0 + || (c3 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 + || c3 < 0 + || (c4 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 + || c4 < 0) { + throw new InvalidInputException(INVALID_UNICODE_ESCAPE); + } else { + this.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + } + } + //handle the \\u case manually into comment + if (this.currentCharacter == '\\') { + if (this.source[this.currentPosition] == '\\') + this.currentPosition++; + } //jump over the \\ + } + /* + * We need to completely consume the line break + */ + if (this.currentCharacter == '\r' + && this.source.length > this.currentPosition) { + if (this.source[this.currentPosition] == '\n') { + this.currentPosition++; + this.currentCharacter = '\n'; + } else if ((this.source[this.currentPosition] == '\\') + && (this.source[this.currentPosition + 1] == 'u')) { + isUnicode = true; + char unicodeChar; + int index = this.currentPosition + 1; + index++; + while (this.source[index] == 'u') { + index++; + } + //-------------unicode traitement ------------ + int c1 = 0, c2 = 0, c3 = 0, c4 = 0; + if ((c1 = Character.getNumericValue(this.source[index++])) > 15 + || c1 < 0 + || (c2 = Character.getNumericValue(this.source[index++])) > 15 + || c2 < 0 + || (c3 = Character.getNumericValue(this.source[index++])) > 15 + || c3 < 0 + || (c4 = Character.getNumericValue(this.source[index++])) > 15 + || c4 < 0) { + this.currentPosition = index; + throw new InvalidInputException(INVALID_UNICODE_ESCAPE); + } else { + unicodeChar = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + } + if (unicodeChar == '\n') { + this.currentPosition = index; + this.currentCharacter = '\n'; + } + } + } + recordComment(TokenNameCOMMENT_LINE); + if (this.taskTags != null) checkTaskTag(this.startPosition, this.currentPosition); + if ((this.currentCharacter == '\r') || (this.currentCharacter == '\n')) { + checkNonExternalizedString(); + if (this.recordLineSeparator) { + if (isUnicode) { + pushUnicodeLineSeparator(); + } else { + pushLineSeparator(); + } + } else { + this.currentLine = null; + } + } + if (this.tokenizeComments) { + return TokenNameCOMMENT_LINE; + } + } catch (IndexOutOfBoundsException e) { + this.currentPosition--; + recordComment(TokenNameCOMMENT_LINE); + if (this.taskTags != null) checkTaskTag(this.startPosition, this.currentPosition); + if (this.tokenizeComments) { + return TokenNameCOMMENT_LINE; + } else { + this.currentPosition++; + } + } + break; + } + if (test > 0) { //traditional and javadoc comment + try { //get the next char + boolean isJavadoc = false, star = false; + boolean isUnicode = false; + // consume next character + this.unicodeAsBackSlash = false; + if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') + && (this.source[this.currentPosition] == 'u')) { + getNextUnicodeChar(); + isUnicode = true; + } else { + isUnicode = false; + if (this.withoutUnicodePtr != 0) { + unicodeStoreAt(++this.withoutUnicodePtr); + } + } + + if (this.currentCharacter == '*') { + isJavadoc = true; + star = true; + } + if ((this.currentCharacter == '\r') || (this.currentCharacter == '\n')) { + checkNonExternalizedString(); + if (this.recordLineSeparator) { + if (!isUnicode) { + pushLineSeparator(); + } + } else { + this.currentLine = null; + } + } + isUnicode = false; + if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') + && (this.source[this.currentPosition] == 'u')) { + //-------------unicode traitement ------------ + getNextUnicodeChar(); + isUnicode = true; + } else { + isUnicode = false; + } + //handle the \\u case manually into comment + if (this.currentCharacter == '\\') { + if (this.source[this.currentPosition] == '\\') + this.currentPosition++; //jump over the \\ + } + // empty comment is not a javadoc /**/ + if (this.currentCharacter == '/') { + isJavadoc = false; + } + //loop until end of comment */ + while ((this.currentCharacter != '/') || (!star)) { + if ((this.currentCharacter == '\r') || (this.currentCharacter == '\n')) { + checkNonExternalizedString(); + if (this.recordLineSeparator) { + if (!isUnicode) { + pushLineSeparator(); + } + } else { + this.currentLine = null; + } + } + star = this.currentCharacter == '*'; + //get next char + if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') + && (this.source[this.currentPosition] == 'u')) { + //-------------unicode traitement ------------ + getNextUnicodeChar(); + isUnicode = true; + } else { + isUnicode = false; + } + //handle the \\u case manually into comment + if (this.currentCharacter == '\\') { + if (this.source[this.currentPosition] == '\\') + this.currentPosition++; + } //jump over the \\ + } + int token = isJavadoc ? TokenNameCOMMENT_JAVADOC : TokenNameCOMMENT_BLOCK; + recordComment(token); + if (this.taskTags != null) checkTaskTag(this.startPosition, this.currentPosition); + if (this.tokenizeComments) { + /* + if (isJavadoc) + return TokenNameCOMMENT_JAVADOC; + return TokenNameCOMMENT_BLOCK; + */ + return token; + } + } catch (IndexOutOfBoundsException e) { + this.currentPosition--; + throw new InvalidInputException(UNTERMINATED_COMMENT); + } + break; + } + if (getNextChar('=')) + return TokenNameDIVIDE_EQUAL; + return TokenNameDIVIDE; + } + case '\u001a' : + if (atEnd()) + return TokenNameEOF; + //the atEnd may not be if source is only some part of a real (external) stream + throw new InvalidInputException("Ctrl-Z"); //$NON-NLS-1$ + + default : + if (Character.isJavaIdentifierStart(this.currentCharacter)) + return scanIdentifierOrKeyword(); + if (isDigit(this.currentCharacter)) + return scanNumber(false); + return TokenNameERROR; + } + } + } //-----------------end switch while try-------------------- + catch (IndexOutOfBoundsException e) { + if (this.tokenizeWhiteSpace && (whiteStart != this.currentPosition - 1)) { + // reposition scanner in case we are interested by spaces as tokens + this.currentPosition--; + this.startPosition = whiteStart; + return TokenNameWHITESPACE; + } + } + return TokenNameEOF; +} +public final void getNextUnicodeChar() + throws InvalidInputException { + //VOID + //handle the case of unicode. + //when a unicode appears then we must use a buffer that holds char internal values + //At the end of this method currentCharacter holds the new visited char + //and currentPosition points right next after it + + //ALL getNextChar.... ARE OPTIMIZED COPIES + + try { + int c1 = 0, c2 = 0, c3 = 0, c4 = 0, unicodeSize = 6; + this.currentPosition++; + while (this.source[this.currentPosition] == 'u') { + this.currentPosition++; + unicodeSize++; + } + + if ((c1 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 + || c1 < 0 + || (c2 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 + || c2 < 0 + || (c3 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 + || c3 < 0 + || (c4 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 + || c4 < 0){ + throw new InvalidInputException(INVALID_UNICODE_ESCAPE); + } else { + this.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + //need the unicode buffer + if (this.withoutUnicodePtr == 0) { + //buffer all the entries that have been left aside.... + unicodeInitializeBuffer(this.currentPosition - unicodeSize - this.startPosition); + } + //fill the buffer with the char + unicodeStoreAt(++this.withoutUnicodePtr); + } + this.unicodeAsBackSlash = this.currentCharacter == '\\'; + } catch (ArrayIndexOutOfBoundsException e) { + this.currentPosition--; + throw new InvalidInputException(INVALID_UNICODE_ESCAPE); + } +} + +public char[] getSource(){ + return this.source; +} +private boolean isDigit(char c) throws InvalidInputException { + if (Character.isDigit(c)) { + switch(c) { + case '0' : + case '1' : + case '2' : + case '3' : + case '4' : + case '5' : + case '6' : + case '7' : + case '8' : + case '9' : + return true; + } + throw new InvalidInputException(Scanner.INVALID_INPUT); + } else { + return false; + } +} +/* Tokenize a method body, assuming that curly brackets are properly balanced. + */ +public final void jumpOverMethodBody() { + + this.wasAcr = false; + int found = 1; + try { + while (true) { //loop for jumping over comments + // ---------Consume white space and handles startPosition--------- + boolean isWhiteSpace; + do { + this.startPosition = this.currentPosition; + if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') + && (this.source[this.currentPosition] == 'u')) { + isWhiteSpace = jumpOverUnicodeWhiteSpace(); + } else { + if (this.recordLineSeparator + && ((this.currentCharacter == '\r') || (this.currentCharacter == '\n'))) + pushLineSeparator(); + isWhiteSpace = CharOperation.isWhitespace(this.currentCharacter); + } + } while (isWhiteSpace); + + // -------consume token until } is found--------- + switch (this.currentCharacter) { + case '{' : + found++; + break; + case '}' : + found--; + if (found == 0) + return; + break; + case '\'' : + { + boolean test; + test = getNextChar('\\'); + if (test) { + try { + scanEscapeCharacter(); + } catch (InvalidInputException ex) { + // ignore + } + } else { + try { // consume next character + this.unicodeAsBackSlash = false; + if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') + && (this.source[this.currentPosition] == 'u')) { + getNextUnicodeChar(); + } else { + if (this.withoutUnicodePtr != 0) { + unicodeStoreAt(++this.withoutUnicodePtr); + } + } + } catch (InvalidInputException ex) { + // ignore + } + } + getNextChar('\''); + break; + } + case '"' : + try { + try { // consume next character + this.unicodeAsBackSlash = false; + if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') + && (this.source[this.currentPosition] == 'u')) { + getNextUnicodeChar(); + } else { + if (this.withoutUnicodePtr != 0) { + unicodeStoreAt(++this.withoutUnicodePtr); + } + } + } catch (InvalidInputException ex) { + // ignore + } + while (this.currentCharacter != '"') { + if (this.currentCharacter == '\r'){ + if (this.source[this.currentPosition] == '\n') this.currentPosition++; + break; // the string cannot go further that the line + } + if (this.currentCharacter == '\n'){ + break; // the string cannot go further that the line + } + if (this.currentCharacter == '\\') { + try { + scanEscapeCharacter(); + } catch (InvalidInputException ex) { + // ignore + } + } + try { // consume next character + this.unicodeAsBackSlash = false; + if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') + && (this.source[this.currentPosition] == 'u')) { + getNextUnicodeChar(); + } else { + if (this.withoutUnicodePtr != 0) { + unicodeStoreAt(++this.withoutUnicodePtr); + } + } + } catch (InvalidInputException ex) { + // ignore + } + } + } catch (IndexOutOfBoundsException e) { + return; + } + break; + case '/' : + { + int test; + if ((test = getNextChar('/', '*')) == 0) { //line comment + try { + this.lastCommentLinePosition = this.currentPosition; + //get the next char + if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') + && (this.source[this.currentPosition] == 'u')) { + //-------------unicode traitement ------------ + int c1 = 0, c2 = 0, c3 = 0, c4 = 0; + this.currentPosition++; + while (this.source[this.currentPosition] == 'u') { + this.currentPosition++; + } + if ((c1 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 + || c1 < 0 + || (c2 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 + || c2 < 0 + || (c3 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 + || c3 < 0 + || (c4 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 + || c4 < 0) { //error don't care of the value + this.currentCharacter = 'A'; + } //something different from \n and \r + else { + this.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + } + } + //handle the \\u case manually into comment + if (this.currentCharacter == '\\') { + if (this.source[this.currentPosition] == '\\') + this.currentPosition++; + } //jump over the \\ + boolean isUnicode = false; + while (this.currentCharacter != '\r' && this.currentCharacter != '\n') { + this.lastCommentLinePosition = this.currentPosition; + //get the next char + isUnicode = false; + if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') + && (this.source[this.currentPosition] == 'u')) { + isUnicode = true; + //-------------unicode traitement ------------ + int c1 = 0, c2 = 0, c3 = 0, c4 = 0; + this.currentPosition++; + while (this.source[this.currentPosition] == 'u') { + this.currentPosition++; + } + if ((c1 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 + || c1 < 0 + || (c2 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 + || c2 < 0 + || (c3 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 + || c3 < 0 + || (c4 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 + || c4 < 0) { //error don't care of the value + this.currentCharacter = 'A'; + } //something different from \n and \r + else { + this.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + } + } + //handle the \\u case manually into comment + if (this.currentCharacter == '\\') { + if (this.source[this.currentPosition] == '\\') + this.currentPosition++; + } //jump over the \\ + } + /* + * We need to completely consume the line break + */ + if (this.currentCharacter == '\r' + && this.source.length > this.currentPosition) { + if (this.source[this.currentPosition] == '\n') { + this.currentPosition++; + this.currentCharacter = '\n'; + } else if ((this.source[this.currentPosition] == '\\') + && (this.source[this.currentPosition + 1] == 'u')) { + isUnicode = true; + char unicodeChar; + int index = this.currentPosition + 1; + index++; + while (this.source[index] == 'u') { + index++; + } + //-------------unicode traitement ------------ + int c1 = 0, c2 = 0, c3 = 0, c4 = 0; + if ((c1 = Character.getNumericValue(this.source[index++])) > 15 + || c1 < 0 + || (c2 = Character.getNumericValue(this.source[index++])) > 15 + || c2 < 0 + || (c3 = Character.getNumericValue(this.source[index++])) > 15 + || c3 < 0 + || (c4 = Character.getNumericValue(this.source[index++])) > 15 + || c4 < 0) { //error don't care of the value + unicodeChar = 'A'; + } else { + unicodeChar = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + } + if (unicodeChar == '\n') { + this.currentPosition = index; + this.currentCharacter = '\n'; + } + } + } + recordComment(TokenNameCOMMENT_LINE); + if (this.recordLineSeparator + && ((this.currentCharacter == '\r') || (this.currentCharacter == '\n'))) { + if (isUnicode) { + pushUnicodeLineSeparator(); + } else { + pushLineSeparator(); + } + } + } catch (IndexOutOfBoundsException e) { + //an eof will then be generated + this.currentPosition--; + recordComment(TokenNameCOMMENT_LINE); + if (!this.tokenizeComments) { + this.currentPosition++; + } + } + break; + } + if (test > 0) { //traditional and javadoc comment + boolean isJavadoc = false; + try { //get the next char + boolean star = false; + boolean isUnicode = false; + // consume next character + this.unicodeAsBackSlash = false; + if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') + && (this.source[this.currentPosition] == 'u')) { + getNextUnicodeChar(); + isUnicode = true; + } else { + isUnicode = false; + if (this.withoutUnicodePtr != 0) { + unicodeStoreAt(++this.withoutUnicodePtr); + } + } + + if (this.currentCharacter == '*') { + isJavadoc = true; + star = true; + } + if ((this.currentCharacter == '\r') || (this.currentCharacter == '\n')) { + if (this.recordLineSeparator) { + if (isUnicode) { + pushUnicodeLineSeparator(); + } else { + pushLineSeparator(); + } + } else { + this.currentLine = null; + } + } + isUnicode = false; + if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') + && (this.source[this.currentPosition] == 'u')) { + //-------------unicode traitement ------------ + getNextUnicodeChar(); + isUnicode = true; + } else { + isUnicode = false; + } + //handle the \\u case manually into comment + if (this.currentCharacter == '\\') { + if (this.source[this.currentPosition] == '\\') + this.currentPosition++; //jump over the \\ + } + // empty comment is not a javadoc /**/ + if (this.currentCharacter == '/') { + isJavadoc = false; + } + //loop until end of comment */ + while ((this.currentCharacter != '/') || (!star)) { + if ((this.currentCharacter == '\r') || (this.currentCharacter == '\n')) { + if (this.recordLineSeparator) { + if (isUnicode) { + pushUnicodeLineSeparator(); + } else { + pushLineSeparator(); + } + } else { + this.currentLine = null; + } + } + star = this.currentCharacter == '*'; + //get next char + if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') + && (this.source[this.currentPosition] == 'u')) { + //-------------unicode traitement ------------ + getNextUnicodeChar(); + isUnicode = true; + } else { + isUnicode = false; + } + //handle the \\u case manually into comment + if (this.currentCharacter == '\\') { + if (this.source[this.currentPosition] == '\\') + this.currentPosition++; + } //jump over the \\ + } + recordComment(isJavadoc ? TokenNameCOMMENT_JAVADOC : TokenNameCOMMENT_BLOCK); + } catch (IndexOutOfBoundsException e) { + return; + } + break; + } + break; + } + + default : + if (Character.isJavaIdentifierStart(this.currentCharacter)) { + scanIdentifierOrKeyword(); + break; + } + if (isDigit(this.currentCharacter)) { + try { + scanNumber(false); + } catch (InvalidInputException ex) { + // ignore + } + break; + } + } + } + //-----------------end switch while try-------------------- + } catch (IndexOutOfBoundsException e) { + // ignore + } catch (InvalidInputException e) { + // ignore + } + return; +} +public final boolean jumpOverUnicodeWhiteSpace() throws InvalidInputException { + //BOOLEAN + //handle the case of unicode. Jump over the next whiteSpace + //making startPosition pointing on the next available char + //On false, the currentCharacter is filled up with a potential + //correct char + + try { + this.wasAcr = false; + int c1, c2, c3, c4; + int unicodeSize = 6; + this.currentPosition++; + while (this.source[this.currentPosition] == 'u') { + this.currentPosition++; + unicodeSize++; + } + + if (((c1 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 + || c1 < 0) + || ((c2 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c2 < 0) + || ((c3 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c3 < 0) + || ((c4 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c4 < 0)) { + throw new InvalidInputException(INVALID_UNICODE_ESCAPE); + } + + this.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + if (CharOperation.isWhitespace(this.currentCharacter)) + return true; + + //buffer the new char which is not a white space + unicodeStoreAt(++this.withoutUnicodePtr); + //this.withoutUnicodePtr == 1 is true here + return false; + } catch (IndexOutOfBoundsException e){ + this.currentPosition--; + throw new InvalidInputException(INVALID_UNICODE_ESCAPE); + } +} + +final char[] optimizedCurrentTokenSource1() { + //return always the same char[] build only once + + //optimization at no speed cost of 99.5 % of the singleCharIdentifier + char charOne = this.source[this.startPosition]; + switch (charOne) { + case 'a' : + return charArray_a; + case 'b' : + return charArray_b; + case 'c' : + return charArray_c; + case 'd' : + return charArray_d; + case 'e' : + return charArray_e; + case 'f' : + return charArray_f; + case 'g' : + return charArray_g; + case 'h' : + return charArray_h; + case 'i' : + return charArray_i; + case 'j' : + return charArray_j; + case 'k' : + return charArray_k; + case 'l' : + return charArray_l; + case 'm' : + return charArray_m; + case 'n' : + return charArray_n; + case 'o' : + return charArray_o; + case 'p' : + return charArray_p; + case 'q' : + return charArray_q; + case 'r' : + return charArray_r; + case 's' : + return charArray_s; + case 't' : + return charArray_t; + case 'u' : + return charArray_u; + case 'v' : + return charArray_v; + case 'w' : + return charArray_w; + case 'x' : + return charArray_x; + case 'y' : + return charArray_y; + case 'z' : + return charArray_z; + default : + return new char[] {charOne}; + } +} +final char[] optimizedCurrentTokenSource2() { + //try to return the same char[] build only once + + char c0, c1; + int hash = + (((c0 = this.source[this.startPosition]) << 6) + (c1 = this.source[this.startPosition + 1])) + % TableSize; + char[][] table = this.charArray_length[0][hash]; + int i = newEntry2; + while (++i < InternalTableSize) { + char[] charArray = table[i]; + if ((c0 == charArray[0]) && (c1 == charArray[1])) + return charArray; + } + //---------other side--------- + i = -1; + int max = newEntry2; + while (++i <= max) { + char[] charArray = table[i]; + if ((c0 == charArray[0]) && (c1 == charArray[1])) + return charArray; + } + //--------add the entry------- + if (++max >= InternalTableSize) max = 0; + char[] r; + table[max] = (r = new char[] {c0, c1}); + newEntry2 = max; + return r; +} +final char[] optimizedCurrentTokenSource3() { + //try to return the same char[] build only once + + char c0, c1, c2; + int hash = + (((c0 = this.source[this.startPosition]) << 12) + + ((c1 = this.source[this.startPosition + 1]) << 6) + + (c2 = this.source[this.startPosition + 2])) + % TableSize; + char[][] table = this.charArray_length[1][hash]; + int i = newEntry3; + while (++i < InternalTableSize) { + char[] charArray = table[i]; + if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2])) + return charArray; + } + //---------other side--------- + i = -1; + int max = newEntry3; + while (++i <= max) { + char[] charArray = table[i]; + if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2])) + return charArray; + } + //--------add the entry------- + if (++max >= InternalTableSize) max = 0; + char[] r; + table[max] = (r = new char[] {c0, c1, c2}); + newEntry3 = max; + return r; +} +final char[] optimizedCurrentTokenSource4() { + //try to return the same char[] build only once + + char c0, c1, c2, c3; + long hash = + ((((long) (c0 = this.source[this.startPosition])) << 18) + + ((c1 = this.source[this.startPosition + 1]) << 12) + + ((c2 = this.source[this.startPosition + 2]) << 6) + + (c3 = this.source[this.startPosition + 3])) + % TableSize; + char[][] table = this.charArray_length[2][(int) hash]; + int i = newEntry4; + while (++i < InternalTableSize) { + char[] charArray = table[i]; + if ((c0 == charArray[0]) + && (c1 == charArray[1]) + && (c2 == charArray[2]) + && (c3 == charArray[3])) + return charArray; + } + //---------other side--------- + i = -1; + int max = newEntry4; + while (++i <= max) { + char[] charArray = table[i]; + if ((c0 == charArray[0]) + && (c1 == charArray[1]) + && (c2 == charArray[2]) + && (c3 == charArray[3])) + return charArray; + } + //--------add the entry------- + if (++max >= InternalTableSize) max = 0; + char[] r; + table[max] = (r = new char[] {c0, c1, c2, c3}); + newEntry4 = max; + return r; + +} +final char[] optimizedCurrentTokenSource5() { + //try to return the same char[] build only once + + char c0, c1, c2, c3, c4; + long hash = + ((((long) (c0 = this.source[this.startPosition])) << 24) + + (((long) (c1 = this.source[this.startPosition + 1])) << 18) + + ((c2 = this.source[this.startPosition + 2]) << 12) + + ((c3 = this.source[this.startPosition + 3]) << 6) + + (c4 = this.source[this.startPosition + 4])) + % TableSize; + char[][] table = this.charArray_length[3][(int) hash]; + int i = newEntry5; + while (++i < InternalTableSize) { + char[] charArray = table[i]; + if ((c0 == charArray[0]) + && (c1 == charArray[1]) + && (c2 == charArray[2]) + && (c3 == charArray[3]) + && (c4 == charArray[4])) + return charArray; + } + //---------other side--------- + i = -1; + int max = newEntry5; + while (++i <= max) { + char[] charArray = table[i]; + if ((c0 == charArray[0]) + && (c1 == charArray[1]) + && (c2 == charArray[2]) + && (c3 == charArray[3]) + && (c4 == charArray[4])) + return charArray; + } + //--------add the entry------- + if (++max >= InternalTableSize) max = 0; + char[] r; + table[max] = (r = new char[] {c0, c1, c2, c3, c4}); + newEntry5 = max; + return r; + +} +final char[] optimizedCurrentTokenSource6() { + //try to return the same char[] build only once + + char c0, c1, c2, c3, c4, c5; + long hash = + ((((long) (c0 = this.source[this.startPosition])) << 32) + + (((long) (c1 = this.source[this.startPosition + 1])) << 24) + + (((long) (c2 = this.source[this.startPosition + 2])) << 18) + + ((c3 = this.source[this.startPosition + 3]) << 12) + + ((c4 = this.source[this.startPosition + 4]) << 6) + + (c5 = this.source[this.startPosition + 5])) + % TableSize; + char[][] table = this.charArray_length[4][(int) hash]; + int i = newEntry6; + while (++i < InternalTableSize) { + char[] charArray = table[i]; + if ((c0 == charArray[0]) + && (c1 == charArray[1]) + && (c2 == charArray[2]) + && (c3 == charArray[3]) + && (c4 == charArray[4]) + && (c5 == charArray[5])) + return charArray; + } + //---------other side--------- + i = -1; + int max = newEntry6; + while (++i <= max) { + char[] charArray = table[i]; + if ((c0 == charArray[0]) + && (c1 == charArray[1]) + && (c2 == charArray[2]) + && (c3 == charArray[3]) + && (c4 == charArray[4]) + && (c5 == charArray[5])) + return charArray; + } + //--------add the entry------- + if (++max >= InternalTableSize) max = 0; + char[] r; + table[max] = (r = new char[] {c0, c1, c2, c3, c4, c5}); + newEntry6 = max; + return r; +} +private void parseTags(NLSLine line) { + String s = new String(getCurrentTokenSource()); + int pos = s.indexOf(TAG_PREFIX); + int lineLength = line.size(); + while (pos != -1) { + int start = pos + TAG_PREFIX_LENGTH; + int end = s.indexOf(TAG_POSTFIX, start); + if (end != -1) { + String index = s.substring(start, end); + int i = 0; + try { + i = Integer.parseInt(index) - 1; // Tags are one based not zero based. + } catch (NumberFormatException e) { + i = -1; // we don't want to consider this as a valid NLS tag + } + if (line.exists(i)) { + line.set(i, null); + } + } + pos = s.indexOf(TAG_PREFIX, start); + } + + this.nonNLSStrings = new StringLiteral[lineLength]; + int nonNLSCounter = 0; + for (Iterator iterator = line.iterator(); iterator.hasNext(); ) { + StringLiteral literal = (StringLiteral) iterator.next(); + if (literal != null) { + this.nonNLSStrings[nonNLSCounter++] = literal; + } + } + if (nonNLSCounter == 0) { + this.nonNLSStrings = null; + this.currentLine = null; + return; + } + this.wasNonExternalizedStringLiteral = true; + if (nonNLSCounter != lineLength) { + System.arraycopy(this.nonNLSStrings, 0, (this.nonNLSStrings = new StringLiteral[nonNLSCounter]), 0, nonNLSCounter); + } + this.currentLine = null; +} + +public final void pushLineSeparator() { + //see comment on isLineDelimiter(char) for the use of '\n' and '\r' + final int INCREMENT = 250; + + if (this.checkNonExternalizedStringLiterals) { + // reinitialize the current line for non externalize strings purpose + this.currentLine = null; + } + //currentCharacter is at position currentPosition-1 + + // cr 000D + if (this.currentCharacter == '\r') { + int separatorPos = this.currentPosition - 1; + //TODO (olivier) david - why the following line was "if ((this.linePtr > 0) && (this.lineEnds[this.linePtr] >= separatorPos)) return;" ? + if ((this.linePtr >= 0) && (this.lineEnds[this.linePtr] >= separatorPos)) return; + //System.out.println("CR-" + separatorPos); + int length = this.lineEnds.length; + if (++this.linePtr >= length) + System.arraycopy(this.lineEnds, 0, this.lineEnds = new int[length + INCREMENT], 0, length); + this.lineEnds[this.linePtr] = separatorPos; + // look-ahead for merged cr+lf + try { + if (this.source[this.currentPosition] == '\n') { + //System.out.println("look-ahead LF-" + this.currentPosition); + this.lineEnds[this.linePtr] = this.currentPosition; + this.currentPosition++; + this.wasAcr = false; + } else { + this.wasAcr = true; + } + } catch(IndexOutOfBoundsException e) { + this.wasAcr = true; + } + } else { + // lf 000A + if (this.currentCharacter == '\n') { //must merge eventual cr followed by lf + if (this.wasAcr && (this.lineEnds[this.linePtr] == (this.currentPosition - 2))) { + //System.out.println("merge LF-" + (this.currentPosition - 1)); + this.lineEnds[this.linePtr] = this.currentPosition - 1; + } else { + int separatorPos = this.currentPosition - 1; + //TODO (olivier) david - why the following line was "if ((this.linePtr > 0) && (this.lineEnds[this.linePtr] >= separatorPos)) return;" ? + if ((this.linePtr >= 0) && (this.lineEnds[this.linePtr] >= separatorPos)) return; + // System.out.println("LF-" + separatorPos); + int length = this.lineEnds.length; + if (++this.linePtr >= length) + System.arraycopy(this.lineEnds, 0, this.lineEnds = new int[length + INCREMENT], 0, length); + this.lineEnds[this.linePtr] = separatorPos; + } + this.wasAcr = false; + } + } +} +public final void pushUnicodeLineSeparator() { + if (this.checkNonExternalizedStringLiterals) { + // reinitialize the current line for non externalize strings purpose + this.currentLine = null; + } + + // cr 000D + if (this.currentCharacter == '\r') { + if (this.source[this.currentPosition] == '\n') { + this.wasAcr = false; + } else { + this.wasAcr = true; + } + } else { + // lf 000A + if (this.currentCharacter == '\n') { //must merge eventual cr followed by lf + this.wasAcr = false; + } + } +} +public void recordComment(int token) { + // compute position + int stopPosition = this.currentPosition; + switch (token) { + case TokenNameCOMMENT_LINE: + stopPosition = -this.lastCommentLinePosition; + break; + case TokenNameCOMMENT_BLOCK: + stopPosition = -this.currentPosition; + break; + } + + // a new comment is recorded + int length = this.commentStops.length; + if (++this.commentPtr >= length) { + System.arraycopy(this.commentStops, 0, this.commentStops = new int[length + 30], 0, length); + //grows the positions buffers too + System.arraycopy(this.commentStarts, 0, this.commentStarts = new int[length + 30], 0, length); + } + this.commentStops[this.commentPtr] = stopPosition; + this.commentStarts[this.commentPtr] = this.startPosition; +} + +/** + * Reposition the scanner on some portion of the original source. The given endPosition is the last valid position. + * Beyond this position, the scanner will answer EOF tokens (ITerminalSymbols.TokenNameEOF). + * + * @param begin the given start position + * @param end the given end position + */ +public void resetTo(int begin, int end) { + //reset the scanner to a given position where it may rescan again + + this.diet = false; + this.initialPosition = this.startPosition = this.currentPosition = begin; + this.eofPosition = end < Integer.MAX_VALUE ? end + 1 : end; + this.commentPtr = -1; // reset comment stack + this.foundTaskCount = 0; + +// // if resetTo is used with being > than end. +// if (begin > this.eofPosition) { +// begin = this.eofPosition; +// } +} + +public final void scanEscapeCharacter() throws InvalidInputException { + // the string with "\\u" is a legal string of two chars \ and u + //thus we use a direct access to the source (for regular cases). + + if (this.unicodeAsBackSlash) { + // consume next character + this.unicodeAsBackSlash = false; + if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') && (this.source[this.currentPosition] == 'u')) { + getNextUnicodeChar(); + } else { + if (this.withoutUnicodePtr != 0) { + unicodeStoreAt(++this.withoutUnicodePtr); + } + } + } else + this.currentCharacter = this.source[this.currentPosition++]; + switch (this.currentCharacter) { + case 'b' : + this.currentCharacter = '\b'; + break; + case 't' : + this.currentCharacter = '\t'; + break; + case 'n' : + this.currentCharacter = '\n'; + break; + case 'f' : + this.currentCharacter = '\f'; + break; + case 'r' : + this.currentCharacter = '\r'; + break; + case '\"' : + this.currentCharacter = '\"'; + break; + case '\'' : + this.currentCharacter = '\''; + break; + case '\\' : + this.currentCharacter = '\\'; + break; + default : + // -----------octal escape-------------- + // OctalDigit + // OctalDigit OctalDigit + // ZeroToThree OctalDigit OctalDigit + + int number = Character.getNumericValue(this.currentCharacter); + if (number >= 0 && number <= 7) { + boolean zeroToThreeNot = number > 3; + if (isDigit(this.currentCharacter = this.source[this.currentPosition++])) { + int digit = Character.getNumericValue(this.currentCharacter); + if (digit >= 0 && digit <= 7) { + number = (number * 8) + digit; + if (isDigit(this.currentCharacter = this.source[this.currentPosition++])) { + if (zeroToThreeNot) {// has read \NotZeroToThree OctalDigit Digit --> ignore last character + this.currentPosition--; + } else { + digit = Character.getNumericValue(this.currentCharacter); + if (digit >= 0 && digit <= 7){ // has read \ZeroToThree OctalDigit OctalDigit + number = (number * 8) + digit; + } else {// has read \ZeroToThree OctalDigit NonOctalDigit --> ignore last character + this.currentPosition--; + } + } + } else { // has read \OctalDigit NonDigit--> ignore last character + this.currentPosition--; + } + } else { // has read \OctalDigit NonOctalDigit--> ignore last character + this.currentPosition--; + } + } else { // has read \OctalDigit --> ignore last character + this.currentPosition--; + } + if (number > 255) + throw new InvalidInputException(INVALID_ESCAPE); + this.currentCharacter = (char) number; + } else + throw new InvalidInputException(INVALID_ESCAPE); + } +} +public int scanIdentifierOrKeyword() { + //test keywords + + //first dispatch on the first char. + //then the length. If there are several + //keywors with the same length AND the same first char, then do another + //dispatch on the second char + this.useAssertAsAnIndentifier = false; + while (getNextCharAsJavaIdentifierPart()){/*empty*/} + + int index, length; + char[] data; + char firstLetter; + if (this.withoutUnicodePtr == 0) + + //quick test on length == 1 but not on length > 12 while most identifier + //have a length which is <= 12...but there are lots of identifier with + //only one char.... + + { + if ((length = this.currentPosition - this.startPosition) == 1) + return TokenNameIdentifier; + data = this.source; + index = this.startPosition; + } else { + if ((length = this.withoutUnicodePtr) == 1) + return TokenNameIdentifier; + data = this.withoutUnicodeBuffer; + index = 1; + } + + firstLetter = data[index]; + switch (firstLetter) { + + case 'a' : + switch(length) { + case 8: //abstract + if ((data[++index] == 'b') + && (data[++index] == 's') + && (data[++index] == 't') + && (data[++index] == 'r') + && (data[++index] == 'a') + && (data[++index] == 'c') + && (data[++index] == 't')) { + return TokenNameabstract; + } else { + return TokenNameIdentifier; + } + case 6: // assert + if ((data[++index] == 's') + && (data[++index] == 's') + && (data[++index] == 'e') + && (data[++index] == 'r') + && (data[++index] == 't')) { + if (this.assertMode) { + this.containsAssertKeyword = true; + return TokenNameassert; + } else { + this.useAssertAsAnIndentifier = true; + return TokenNameIdentifier; + } + } else { + return TokenNameIdentifier; + } + default: + return TokenNameIdentifier; + } + case 'b' : //boolean break byte + switch (length) { + case 4 : + if ((data[++index] == 'y') && (data[++index] == 't') && (data[++index] == 'e')) + return TokenNamebyte; + else + return TokenNameIdentifier; + case 5 : + if ((data[++index] == 'r') + && (data[++index] == 'e') + && (data[++index] == 'a') + && (data[++index] == 'k')) + return TokenNamebreak; + else + return TokenNameIdentifier; + case 7 : + if ((data[++index] == 'o') + && (data[++index] == 'o') + && (data[++index] == 'l') + && (data[++index] == 'e') + && (data[++index] == 'a') + && (data[++index] == 'n')) + return TokenNameboolean; + else + return TokenNameIdentifier; + default : + return TokenNameIdentifier; + } + + case 'c' : //case char catch const class continue + switch (length) { + case 4 : + if (data[++index] == 'a') + if ((data[++index] == 's') && (data[++index] == 'e')) + return TokenNamecase; + else + return TokenNameIdentifier; + else + if ((data[index] == 'h') && (data[++index] == 'a') && (data[++index] == 'r')) + return TokenNamechar; + else + return TokenNameIdentifier; + case 5 : + if (data[++index] == 'a') + if ((data[++index] == 't') && (data[++index] == 'c') && (data[++index] == 'h')) + return TokenNamecatch; + else + return TokenNameIdentifier; + else + if (data[index] == 'l') + if ((data[++index] == 'a') + && (data[++index] == 's') + && (data[++index] == 's')) + return TokenNameclass; + else + return TokenNameIdentifier; + else if ((data[index] == 'o') + && (data[++index] == 'n') + && (data[++index] == 's') + && (data[++index] == 't')) + return TokenNameERROR; //const is not used in java ??????? + else + return TokenNameIdentifier; + case 8 : + if ((data[++index] == 'o') + && (data[++index] == 'n') + && (data[++index] == 't') + && (data[++index] == 'i') + && (data[++index] == 'n') + && (data[++index] == 'u') + && (data[++index] == 'e')) + return TokenNamecontinue; + else + return TokenNameIdentifier; + default : + return TokenNameIdentifier; + } + + case 'd' : //default do double + switch (length) { + case 2 : + if ((data[++index] == 'o')) + return TokenNamedo; + else + return TokenNameIdentifier; + case 6 : + if ((data[++index] == 'o') + && (data[++index] == 'u') + && (data[++index] == 'b') + && (data[++index] == 'l') + && (data[++index] == 'e')) + return TokenNamedouble; + else + return TokenNameIdentifier; + case 7 : + if ((data[++index] == 'e') + && (data[++index] == 'f') + && (data[++index] == 'a') + && (data[++index] == 'u') + && (data[++index] == 'l') + && (data[++index] == 't')) + return TokenNamedefault; + else + return TokenNameIdentifier; + default : + return TokenNameIdentifier; + } + case 'e' : //else extends + switch (length) { + case 4 : + if ((data[++index] == 'l') && (data[++index] == 's') && (data[++index] == 'e')) + return TokenNameelse; + else + return TokenNameIdentifier; + case 7 : + if ((data[++index] == 'x') + && (data[++index] == 't') + && (data[++index] == 'e') + && (data[++index] == 'n') + && (data[++index] == 'd') + && (data[++index] == 's')) + return TokenNameextends; + else + return TokenNameIdentifier; + default : + return TokenNameIdentifier; + } + + case 'f' : //final finally float for false + switch (length) { + case 3 : + if ((data[++index] == 'o') && (data[++index] == 'r')) + return TokenNamefor; + else + return TokenNameIdentifier; + case 5 : + if (data[++index] == 'i') + if ((data[++index] == 'n') + && (data[++index] == 'a') + && (data[++index] == 'l')) { + return TokenNamefinal; + } else + return TokenNameIdentifier; + else + if (data[index] == 'l') + if ((data[++index] == 'o') + && (data[++index] == 'a') + && (data[++index] == 't')) + return TokenNamefloat; + else + return TokenNameIdentifier; + else + if ((data[index] == 'a') + && (data[++index] == 'l') + && (data[++index] == 's') + && (data[++index] == 'e')) + return TokenNamefalse; + else + return TokenNameIdentifier; + case 7 : + if ((data[++index] == 'i') + && (data[++index] == 'n') + && (data[++index] == 'a') + && (data[++index] == 'l') + && (data[++index] == 'l') + && (data[++index] == 'y')) + return TokenNamefinally; + else + return TokenNameIdentifier; + + default : + return TokenNameIdentifier; + } + case 'g' : //goto + if (length == 4) { + if ((data[++index] == 'o') + && (data[++index] == 't') + && (data[++index] == 'o')) { + return TokenNameERROR; + } + } //no goto in java are allowed, so why java removes this keyword ??? + return TokenNameIdentifier; + + case 'i' : //if implements import instanceof int interface + switch (length) { + case 2 : + if (data[++index] == 'f') + return TokenNameif; + else + return TokenNameIdentifier; + case 3 : + if ((data[++index] == 'n') && (data[++index] == 't')) + return TokenNameint; + else + return TokenNameIdentifier; + case 6 : + if ((data[++index] == 'm') + && (data[++index] == 'p') + && (data[++index] == 'o') + && (data[++index] == 'r') + && (data[++index] == 't')) + return TokenNameimport; + else + return TokenNameIdentifier; + case 9 : + if ((data[++index] == 'n') + && (data[++index] == 't') + && (data[++index] == 'e') + && (data[++index] == 'r') + && (data[++index] == 'f') + && (data[++index] == 'a') + && (data[++index] == 'c') + && (data[++index] == 'e')) + return TokenNameinterface; + else + return TokenNameIdentifier; + case 10 : + if (data[++index] == 'm') + if ((data[++index] == 'p') + && (data[++index] == 'l') + && (data[++index] == 'e') + && (data[++index] == 'm') + && (data[++index] == 'e') + && (data[++index] == 'n') + && (data[++index] == 't') + && (data[++index] == 's')) + return TokenNameimplements; + else + return TokenNameIdentifier; + else + if ((data[index] == 'n') + && (data[++index] == 's') + && (data[++index] == 't') + && (data[++index] == 'a') + && (data[++index] == 'n') + && (data[++index] == 'c') + && (data[++index] == 'e') + && (data[++index] == 'o') + && (data[++index] == 'f')) + return TokenNameinstanceof; + else + return TokenNameIdentifier; + + default : + return TokenNameIdentifier; + } + + case 'l' : //long + if (length == 4) { + if ((data[++index] == 'o') + && (data[++index] == 'n') + && (data[++index] == 'g')) { + return TokenNamelong; + } + } + return TokenNameIdentifier; + + case 'n' : //native new null + switch (length) { + case 3 : + if ((data[++index] == 'e') && (data[++index] == 'w')) + return TokenNamenew; + else + return TokenNameIdentifier; + case 4 : + if ((data[++index] == 'u') && (data[++index] == 'l') && (data[++index] == 'l')) + return TokenNamenull; + else + return TokenNameIdentifier; + case 6 : + if ((data[++index] == 'a') + && (data[++index] == 't') + && (data[++index] == 'i') + && (data[++index] == 'v') + && (data[++index] == 'e')) { + return TokenNamenative; + } else + return TokenNameIdentifier; + default : + return TokenNameIdentifier; + } + + case 'p' : //package private protected public + switch (length) { + case 6 : + if ((data[++index] == 'u') + && (data[++index] == 'b') + && (data[++index] == 'l') + && (data[++index] == 'i') + && (data[++index] == 'c')) { + return TokenNamepublic; + } else + return TokenNameIdentifier; + case 7 : + if (data[++index] == 'a') + if ((data[++index] == 'c') + && (data[++index] == 'k') + && (data[++index] == 'a') + && (data[++index] == 'g') + && (data[++index] == 'e')) + return TokenNamepackage; + else + return TokenNameIdentifier; + else + if ((data[index] == 'r') + && (data[++index] == 'i') + && (data[++index] == 'v') + && (data[++index] == 'a') + && (data[++index] == 't') + && (data[++index] == 'e')) { + return TokenNameprivate; + } else + return TokenNameIdentifier; + case 9 : + if ((data[++index] == 'r') + && (data[++index] == 'o') + && (data[++index] == 't') + && (data[++index] == 'e') + && (data[++index] == 'c') + && (data[++index] == 't') + && (data[++index] == 'e') + && (data[++index] == 'd')) { + return TokenNameprotected; + } else + return TokenNameIdentifier; + + default : + return TokenNameIdentifier; + } + + case 'r' : //return + if (length == 6) { + if ((data[++index] == 'e') + && (data[++index] == 't') + && (data[++index] == 'u') + && (data[++index] == 'r') + && (data[++index] == 'n')) { + return TokenNamereturn; + } + } + return TokenNameIdentifier; + + case 's' : //short static super switch synchronized strictfp + switch (length) { + case 5 : + if (data[++index] == 'h') + if ((data[++index] == 'o') && (data[++index] == 'r') && (data[++index] == 't')) + return TokenNameshort; + else + return TokenNameIdentifier; + else + if ((data[index] == 'u') + && (data[++index] == 'p') + && (data[++index] == 'e') + && (data[++index] == 'r')) + return TokenNamesuper; + else + return TokenNameIdentifier; + + case 6 : + if (data[++index] == 't') + if ((data[++index] == 'a') + && (data[++index] == 't') + && (data[++index] == 'i') + && (data[++index] == 'c')) { + return TokenNamestatic; + } else + return TokenNameIdentifier; + else + if ((data[index] == 'w') + && (data[++index] == 'i') + && (data[++index] == 't') + && (data[++index] == 'c') + && (data[++index] == 'h')) + return TokenNameswitch; + else + return TokenNameIdentifier; + case 8 : + if ((data[++index] == 't') + && (data[++index] == 'r') + && (data[++index] == 'i') + && (data[++index] == 'c') + && (data[++index] == 't') + && (data[++index] == 'f') + && (data[++index] == 'p')) + return TokenNamestrictfp; + else + return TokenNameIdentifier; + case 12 : + if ((data[++index] == 'y') + && (data[++index] == 'n') + && (data[++index] == 'c') + && (data[++index] == 'h') + && (data[++index] == 'r') + && (data[++index] == 'o') + && (data[++index] == 'n') + && (data[++index] == 'i') + && (data[++index] == 'z') + && (data[++index] == 'e') + && (data[++index] == 'd')) { + return TokenNamesynchronized; + } else + return TokenNameIdentifier; + default : + return TokenNameIdentifier; + } + + case 't' : //try throw throws transient this true + switch (length) { + case 3 : + if ((data[++index] == 'r') && (data[++index] == 'y')) + return TokenNametry; + else + return TokenNameIdentifier; + case 4 : + if (data[++index] == 'h') + if ((data[++index] == 'i') && (data[++index] == 's')) + return TokenNamethis; + else + return TokenNameIdentifier; + else + if ((data[index] == 'r') && (data[++index] == 'u') && (data[++index] == 'e')) + return TokenNametrue; + else + return TokenNameIdentifier; + case 5 : + if ((data[++index] == 'h') + && (data[++index] == 'r') + && (data[++index] == 'o') + && (data[++index] == 'w')) + return TokenNamethrow; + else + return TokenNameIdentifier; + case 6 : + if ((data[++index] == 'h') + && (data[++index] == 'r') + && (data[++index] == 'o') + && (data[++index] == 'w') + && (data[++index] == 's')) + return TokenNamethrows; + else + return TokenNameIdentifier; + case 9 : + if ((data[++index] == 'r') + && (data[++index] == 'a') + && (data[++index] == 'n') + && (data[++index] == 's') + && (data[++index] == 'i') + && (data[++index] == 'e') + && (data[++index] == 'n') + && (data[++index] == 't')) { + return TokenNametransient; + } else + return TokenNameIdentifier; + + default : + return TokenNameIdentifier; + } + + case 'v' : //void volatile + switch (length) { + case 4 : + if ((data[++index] == 'o') && (data[++index] == 'i') && (data[++index] == 'd')) + return TokenNamevoid; + else + return TokenNameIdentifier; + case 8 : + if ((data[++index] == 'o') + && (data[++index] == 'l') + && (data[++index] == 'a') + && (data[++index] == 't') + && (data[++index] == 'i') + && (data[++index] == 'l') + && (data[++index] == 'e')) { + return TokenNamevolatile; + } else + return TokenNameIdentifier; + + default : + return TokenNameIdentifier; + } + + case 'w' : //while widefp + switch (length) { + case 5 : + if ((data[++index] == 'h') + && (data[++index] == 'i') + && (data[++index] == 'l') + && (data[++index] == 'e')) + return TokenNamewhile; + else + return TokenNameIdentifier; + //case 6:if ( (data[++index] =='i') && (data[++index]=='d') && (data[++index]=='e') && (data[++index]=='f')&& (data[++index]=='p')) + //return TokenNamewidefp ; + //else + //return TokenNameIdentifier; + default : + return TokenNameIdentifier; + } + + default : + return TokenNameIdentifier; + } +} +public int scanNumber(boolean dotPrefix) throws InvalidInputException { + + //when entering this method the currentCharacter is the first + //digit of the number. It may be preceeded by a '.' when + //dotPrefix is true + + boolean floating = dotPrefix; + if ((!dotPrefix) && (this.currentCharacter == '0')) { + if (getNextChar('x', 'X') >= 0) { //----------hexa----------------- + //force the first char of the hexa number do exist... + // consume next character + this.unicodeAsBackSlash = false; + if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') + && (this.source[this.currentPosition] == 'u')) { + getNextUnicodeChar(); + } else { + if (this.withoutUnicodePtr != 0) { + unicodeStoreAt(++this.withoutUnicodePtr); + } + } + if (Character.digit(this.currentCharacter, 16) == -1) + throw new InvalidInputException(INVALID_HEXA); + //---end forcing-- + while (getNextCharAsDigit(16)){/*empty*/} + if (getNextChar('l', 'L') >= 0) + return TokenNameLongLiteral; + else + return TokenNameIntegerLiteral; + } + + //there is x or X in the number + //potential octal ! ... some one may write 000099.0 ! thus 00100 < 00078.0 is true !!!!! crazy language + if (getNextCharAsDigit()) { //-------------potential octal----------------- + while (getNextCharAsDigit()){/*empty*/} + + if (getNextChar('l', 'L') >= 0) { + return TokenNameLongLiteral; + } + + if (getNextChar('f', 'F') >= 0) { + return TokenNameFloatingPointLiteral; + } + + if (getNextChar('d', 'D') >= 0) { + return TokenNameDoubleLiteral; + } else { //make the distinction between octal and float .... + boolean isInteger = true; + if (getNextChar('.')) { + isInteger = false; + while (getNextCharAsDigit()){/*empty*/} + } + if (getNextChar('e', 'E') >= 0) { // consume next character + isInteger = false; + this.unicodeAsBackSlash = false; + if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') + && (this.source[this.currentPosition] == 'u')) { + getNextUnicodeChar(); + } else { + if (this.withoutUnicodePtr != 0) { + unicodeStoreAt(++this.withoutUnicodePtr); + } + } + + if ((this.currentCharacter == '-') + || (this.currentCharacter == '+')) { // consume next character + this.unicodeAsBackSlash = false; + if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') + && (this.source[this.currentPosition] == 'u')) { + getNextUnicodeChar(); + } else { + if (this.withoutUnicodePtr != 0) { + unicodeStoreAt(++this.withoutUnicodePtr); + } + } + } + if (!isDigit(this.currentCharacter)) + throw new InvalidInputException(INVALID_FLOAT); + while (getNextCharAsDigit()){/*empty*/} + } + if (getNextChar('f', 'F') >= 0) + return TokenNameFloatingPointLiteral; + if (getNextChar('d', 'D') >= 0 || !isInteger) + return TokenNameDoubleLiteral; + return TokenNameIntegerLiteral; + } + } else { + /* carry on */ + } + } + + while (getNextCharAsDigit()){/*empty*/} + + if ((!dotPrefix) && (getNextChar('l', 'L') >= 0)) + return TokenNameLongLiteral; + + if ((!dotPrefix) && (getNextChar('.'))) { //decimal part that can be empty + while (getNextCharAsDigit()){/*empty*/} + floating = true; + } + + //if floating is true both exponant and suffix may be optional + + if (getNextChar('e', 'E') >= 0) { + floating = true; + // consume next character + this.unicodeAsBackSlash = false; + if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') + && (this.source[this.currentPosition] == 'u')) { + getNextUnicodeChar(); + } else { + if (this.withoutUnicodePtr != 0) { + unicodeStoreAt(++this.withoutUnicodePtr); + } + } + + if ((this.currentCharacter == '-') + || (this.currentCharacter == '+')) { // consume next character + this.unicodeAsBackSlash = false; + if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') + && (this.source[this.currentPosition] == 'u')) { + getNextUnicodeChar(); + } else { + if (this.withoutUnicodePtr != 0) { + unicodeStoreAt(++this.withoutUnicodePtr); + } + } + } + if (!isDigit(this.currentCharacter)) + throw new InvalidInputException(INVALID_FLOAT); + while (getNextCharAsDigit()){/*empty*/} + } + + if (getNextChar('d', 'D') >= 0) + return TokenNameDoubleLiteral; + if (getNextChar('f', 'F') >= 0) + return TokenNameFloatingPointLiteral; + + //the long flag has been tested before + + return floating ? TokenNameDoubleLiteral : TokenNameIntegerLiteral; +} +/** + * Search the line number corresponding to a specific position + * @param position int + * @return int + */ +public final int getLineNumber(int position) { + + if (this.lineEnds == null) + return 1; + int length = this.linePtr+1; + if (length == 0) + return 1; + int g = 0, d = length - 1; + int m = 0; + while (g <= d) { + m = (g + d) /2; + if (position < this.lineEnds[m]) { + d = m-1; + } else if (position > this.lineEnds[m]) { + g = m+1; + } else { + return m + 1; + } + } + if (position < this.lineEnds[m]) { + return m+1; + } + return m+2; +} +public final void setSource(char[] sourceString){ + //the source-buffer is set to sourceString + + int sourceLength; + if (sourceString == null) { + this.source = CharOperation.NO_CHAR; + sourceLength = 0; + } else { + this.source = sourceString; + sourceLength = sourceString.length; + } + this.startPosition = -1; + this.eofPosition = sourceLength; + this.initialPosition = this.currentPosition = 0; + this.containsAssertKeyword = false; +} + +public String toString() { + if (this.startPosition == this.source.length) + return "EOF\n\n" + new String(this.source); //$NON-NLS-1$ + if (this.currentPosition > this.source.length) + return "behind the EOF\n\n" + new String(this.source); //$NON-NLS-1$ + + char front[] = new char[this.startPosition]; + System.arraycopy(this.source, 0, front, 0, this.startPosition); + + int middleLength = (this.currentPosition - 1) - this.startPosition + 1; + char middle[]; + if (middleLength > -1) { + middle = new char[middleLength]; + System.arraycopy( + this.source, + this.startPosition, + middle, + 0, + middleLength); + } else { + middle = CharOperation.NO_CHAR; + } + + char end[] = new char[this.source.length - (this.currentPosition - 1)]; + System.arraycopy( + this.source, + (this.currentPosition - 1) + 1, + end, + 0, + this.source.length - (this.currentPosition - 1) - 1); + + return new String(front) + + "\n===============================\nStarts here -->" //$NON-NLS-1$ + + new String(middle) + + "<-- Ends here\n===============================\n" //$NON-NLS-1$ + + new String(end); +} +public final String toStringAction(int act) { + switch (act) { + case TokenNameIdentifier : + return "Identifier(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + case TokenNameabstract : + return "abstract"; //$NON-NLS-1$ + case TokenNameboolean : + return "boolean"; //$NON-NLS-1$ + case TokenNamebreak : + return "break"; //$NON-NLS-1$ + case TokenNamebyte : + return "byte"; //$NON-NLS-1$ + case TokenNamecase : + return "case"; //$NON-NLS-1$ + case TokenNamecatch : + return "catch"; //$NON-NLS-1$ + case TokenNamechar : + return "char"; //$NON-NLS-1$ + case TokenNameclass : + return "class"; //$NON-NLS-1$ + case TokenNamecontinue : + return "continue"; //$NON-NLS-1$ + case TokenNamedefault : + return "default"; //$NON-NLS-1$ + case TokenNamedo : + return "do"; //$NON-NLS-1$ + case TokenNamedouble : + return "double"; //$NON-NLS-1$ + case TokenNameelse : + return "else"; //$NON-NLS-1$ + case TokenNameextends : + return "extends"; //$NON-NLS-1$ + case TokenNamefalse : + return "false"; //$NON-NLS-1$ + case TokenNamefinal : + return "final"; //$NON-NLS-1$ + case TokenNamefinally : + return "finally"; //$NON-NLS-1$ + case TokenNamefloat : + return "float"; //$NON-NLS-1$ + case TokenNamefor : + return "for"; //$NON-NLS-1$ + case TokenNameif : + return "if"; //$NON-NLS-1$ + case TokenNameimplements : + return "implements"; //$NON-NLS-1$ + case TokenNameimport : + return "import"; //$NON-NLS-1$ + case TokenNameinstanceof : + return "instanceof"; //$NON-NLS-1$ + case TokenNameint : + return "int"; //$NON-NLS-1$ + case TokenNameinterface : + return "interface"; //$NON-NLS-1$ + case TokenNamelong : + return "long"; //$NON-NLS-1$ + case TokenNamenative : + return "native"; //$NON-NLS-1$ + case TokenNamenew : + return "new"; //$NON-NLS-1$ + case TokenNamenull : + return "null"; //$NON-NLS-1$ + case TokenNamepackage : + return "package"; //$NON-NLS-1$ + case TokenNameprivate : + return "private"; //$NON-NLS-1$ + case TokenNameprotected : + return "protected"; //$NON-NLS-1$ + case TokenNamepublic : + return "public"; //$NON-NLS-1$ + case TokenNamereturn : + return "return"; //$NON-NLS-1$ + case TokenNameshort : + return "short"; //$NON-NLS-1$ + case TokenNamestatic : + return "static"; //$NON-NLS-1$ + case TokenNamesuper : + return "super"; //$NON-NLS-1$ + case TokenNameswitch : + return "switch"; //$NON-NLS-1$ + case TokenNamesynchronized : + return "synchronized"; //$NON-NLS-1$ + case TokenNamethis : + return "this"; //$NON-NLS-1$ + case TokenNamethrow : + return "throw"; //$NON-NLS-1$ + case TokenNamethrows : + return "throws"; //$NON-NLS-1$ + case TokenNametransient : + return "transient"; //$NON-NLS-1$ + case TokenNametrue : + return "true"; //$NON-NLS-1$ + case TokenNametry : + return "try"; //$NON-NLS-1$ + case TokenNamevoid : + return "void"; //$NON-NLS-1$ + case TokenNamevolatile : + return "volatile"; //$NON-NLS-1$ + case TokenNamewhile : + return "while"; //$NON-NLS-1$ + + case TokenNameIntegerLiteral : + return "Integer(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + case TokenNameLongLiteral : + return "Long(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + case TokenNameFloatingPointLiteral : + return "Float(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + case TokenNameDoubleLiteral : + return "Double(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + case TokenNameCharacterLiteral : + return "Char(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + case TokenNameStringLiteral : + return "String(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + + case TokenNamePLUS_PLUS : + return "++"; //$NON-NLS-1$ + case TokenNameMINUS_MINUS : + return "--"; //$NON-NLS-1$ + case TokenNameEQUAL_EQUAL : + return "=="; //$NON-NLS-1$ + case TokenNameLESS_EQUAL : + return "<="; //$NON-NLS-1$ + case TokenNameGREATER_EQUAL : + return ">="; //$NON-NLS-1$ + case TokenNameNOT_EQUAL : + return "!="; //$NON-NLS-1$ + case TokenNameLEFT_SHIFT : + return "<<"; //$NON-NLS-1$ + case TokenNameRIGHT_SHIFT : + return ">>"; //$NON-NLS-1$ + case TokenNameUNSIGNED_RIGHT_SHIFT : + return ">>>"; //$NON-NLS-1$ + case TokenNamePLUS_EQUAL : + return "+="; //$NON-NLS-1$ + case TokenNameMINUS_EQUAL : + return "-="; //$NON-NLS-1$ + case TokenNameMULTIPLY_EQUAL : + return "*="; //$NON-NLS-1$ + case TokenNameDIVIDE_EQUAL : + return "/="; //$NON-NLS-1$ + case TokenNameAND_EQUAL : + return "&="; //$NON-NLS-1$ + case TokenNameOR_EQUAL : + return "|="; //$NON-NLS-1$ + case TokenNameXOR_EQUAL : + return "^="; //$NON-NLS-1$ + case TokenNameREMAINDER_EQUAL : + return "%="; //$NON-NLS-1$ + case TokenNameLEFT_SHIFT_EQUAL : + return "<<="; //$NON-NLS-1$ + case TokenNameRIGHT_SHIFT_EQUAL : + return ">>="; //$NON-NLS-1$ + case TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL : + return ">>>="; //$NON-NLS-1$ + case TokenNameOR_OR : + return "||"; //$NON-NLS-1$ + case TokenNameAND_AND : + return "&&"; //$NON-NLS-1$ + case TokenNamePLUS : + return "+"; //$NON-NLS-1$ + case TokenNameMINUS : + return "-"; //$NON-NLS-1$ + case TokenNameNOT : + return "!"; //$NON-NLS-1$ + case TokenNameREMAINDER : + return "%"; //$NON-NLS-1$ + case TokenNameXOR : + return "^"; //$NON-NLS-1$ + case TokenNameAND : + return "&"; //$NON-NLS-1$ + case TokenNameMULTIPLY : + return "*"; //$NON-NLS-1$ + case TokenNameOR : + return "|"; //$NON-NLS-1$ + case TokenNameTWIDDLE : + return "~"; //$NON-NLS-1$ + case TokenNameDIVIDE : + return "/"; //$NON-NLS-1$ + case TokenNameGREATER : + return ">"; //$NON-NLS-1$ + case TokenNameLESS : + return "<"; //$NON-NLS-1$ + case TokenNameLPAREN : + return "("; //$NON-NLS-1$ + case TokenNameRPAREN : + return ")"; //$NON-NLS-1$ + case TokenNameLBRACE : + return "{"; //$NON-NLS-1$ + case TokenNameRBRACE : + return "}"; //$NON-NLS-1$ + case TokenNameLBRACKET : + return "["; //$NON-NLS-1$ + case TokenNameRBRACKET : + return "]"; //$NON-NLS-1$ + case TokenNameSEMICOLON : + return ";"; //$NON-NLS-1$ + case TokenNameQUESTION : + return "?"; //$NON-NLS-1$ + case TokenNameCOLON : + return ":"; //$NON-NLS-1$ + case TokenNameCOMMA : + return ","; //$NON-NLS-1$ + case TokenNameDOT : + return "."; //$NON-NLS-1$ + case TokenNameEQUAL : + return "="; //$NON-NLS-1$ + case TokenNameEOF : + return "EOF"; //$NON-NLS-1$ + default : + return "not-a-token"; //$NON-NLS-1$ + } +} +public void unicodeInitializeBuffer(int length) { + this.withoutUnicodePtr = length; + if (this.withoutUnicodeBuffer == null) this.withoutUnicodeBuffer = new char[length+(1+10)]; + int bLength = this.withoutUnicodeBuffer.length; + if (1+length >= bLength) { + System.arraycopy(this.withoutUnicodeBuffer, 0, this.withoutUnicodeBuffer = new char[length + (1+10)], 0, bLength); + } + System.arraycopy(this.source, this.startPosition, this.withoutUnicodeBuffer, 1, length); +} +public void unicodeStoreAt(int pos) { + if (this.withoutUnicodeBuffer == null) this.withoutUnicodeBuffer = new char[10]; + int length = this.withoutUnicodeBuffer.length; + if (pos == length) { + System.arraycopy(this.withoutUnicodeBuffer, 0, this.withoutUnicodeBuffer = new char[length * 2], 0, length); + } + this.withoutUnicodeBuffer[pos] = this.currentCharacter; +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/TerminalTokens.java b/src/java/org/eclipse/jdt/internal/compiler/parser/TerminalTokens.java new file mode 100644 index 0000000..c05ff33 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/parser/TerminalTokens.java @@ -0,0 +1,145 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.internal.compiler.parser; + +/** + * IMPORTANT NOTE: These constants are dedicated to the internal Scanner implementation. + * It is mirrored in org.eclipse.jdt.core.compiler public package where it is API. + * The mirror implementation is using the backward compatible ITerminalSymbols constant + * definitions (stable with 2.0), whereas the internal implementation uses TerminalTokens + * which constant values reflect the latest parser generation state. + */ + +/** + * Maps each terminal symbol in the java-grammar into a unique integer. + * This integer is used to represent the terminal when computing a parsing action. + * + * Disclaimer : These constant values are generated automatically using a Java + * grammar, therefore their actual values are subject to change if new keywords + * were added to the language (for instance, 'assert' is a keyword in 1.4). + */ +public interface TerminalTokens { + + // special tokens not part of grammar - not autogenerated + int + TokenNameWHITESPACE = 1000, + TokenNameCOMMENT_LINE = 1001, + TokenNameCOMMENT_BLOCK = 1002, + TokenNameCOMMENT_JAVADOC = 1003; + + int + TokenNameIdentifier = 28, + TokenNameabstract = 60, + TokenNameassert = 71, + TokenNameboolean = 31, + TokenNamebreak = 72, + TokenNamebyte = 32, + TokenNamecase = 83, + TokenNamecatch = 86, + TokenNamechar = 33, + TokenNameclass = 81, + TokenNamecontinue = 73, + TokenNamedefault = 84, + TokenNamedo = 74, + TokenNamedouble = 34, + TokenNameelse = 87, + TokenNameextends = 91, + TokenNamefalse = 44, + TokenNamefinal = 61, + TokenNamefinally = 88, + TokenNamefloat = 35, + TokenNamefor = 75, + TokenNameif = 76, + TokenNameimplements = 103, + TokenNameimport = 82, + TokenNameinstanceof = 13, + TokenNameint = 36, + TokenNameinterface = 89, + TokenNamelong = 37, + TokenNamenative = 62, + TokenNamenew = 41, + TokenNamenull = 45, + TokenNamepackage = 85, + TokenNameprivate = 63, + TokenNameprotected = 64, + TokenNamepublic = 65, + TokenNamereturn = 77, + TokenNameshort = 38, + TokenNamestatic = 57, + TokenNamestrictfp = 66, + TokenNamesuper = 42, + TokenNameswitch = 78, + TokenNamesynchronized = 55, + TokenNamethis = 43, + TokenNamethrow = 79, + TokenNamethrows = 104, + TokenNametransient = 67, + TokenNametrue = 46, + TokenNametry = 80, + TokenNamevoid = 39, + TokenNamevolatile = 68, + TokenNamewhile = 70, + TokenNameIntegerLiteral = 47, + TokenNameLongLiteral = 48, + TokenNameFloatingPointLiteral = 49, + TokenNameDoubleLiteral = 50, + TokenNameCharacterLiteral = 51, + TokenNameStringLiteral = 52, + TokenNamePLUS_PLUS = 7, + TokenNameMINUS_MINUS = 8, + TokenNameEQUAL_EQUAL = 18, + TokenNameLESS_EQUAL = 14, + TokenNameGREATER_EQUAL = 15, + TokenNameNOT_EQUAL = 19, + TokenNameLEFT_SHIFT = 11, + TokenNameRIGHT_SHIFT = 9, + TokenNameUNSIGNED_RIGHT_SHIFT = 10, + TokenNamePLUS_EQUAL = 92, + TokenNameMINUS_EQUAL = 93, + TokenNameMULTIPLY_EQUAL = 94, + TokenNameDIVIDE_EQUAL = 95, + TokenNameAND_EQUAL = 96, + TokenNameOR_EQUAL = 97, + TokenNameXOR_EQUAL = 98, + TokenNameREMAINDER_EQUAL = 99, + TokenNameLEFT_SHIFT_EQUAL = 100, + TokenNameRIGHT_SHIFT_EQUAL = 101, + TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL = 102, + TokenNameOR_OR = 24, + TokenNameAND_AND = 25, + TokenNamePLUS = 1, + TokenNameMINUS = 2, + TokenNameNOT = 58, + TokenNameREMAINDER = 5, + TokenNameXOR = 21, + TokenNameAND = 20, + TokenNameMULTIPLY = 4, + TokenNameOR = 22, + TokenNameTWIDDLE = 56, + TokenNameDIVIDE = 6, + TokenNameGREATER = 16, + TokenNameLESS = 17, + TokenNameLPAREN = 27, + TokenNameRPAREN = 29, + TokenNameLBRACE = 59, + TokenNameRBRACE = 40, + TokenNameLBRACKET = 12, + TokenNameRBRACKET = 69, + TokenNameSEMICOLON = 23, + TokenNameQUESTION = 26, + TokenNameCOLON = 53, + TokenNameCOMMA = 30, + TokenNameDOT = 3, + TokenNameEQUAL = 90, + TokenNameEOF = 54, + TokenNameERROR = 105; +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/diagnose/DiagnoseParser.java b/src/java/org/eclipse/jdt/internal/compiler/parser/diagnose/DiagnoseParser.java new file mode 100644 index 0000000..58e0506 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/parser/diagnose/DiagnoseParser.java @@ -0,0 +1,2216 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.parser.diagnose; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.parser.Parser; +import org.eclipse.jdt.internal.compiler.parser.ParserBasicInformation; +import org.eclipse.jdt.internal.compiler.parser.TerminalTokens; +import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; + +public class DiagnoseParser implements ParserBasicInformation, TerminalTokens { + private static final boolean DEBUG = false; + + private static final String EMPTY_STRING = ""; //$NON-NLS-1$ + private static final int STACK_INCREMENT = 256; + +// private static final int ERROR_CODE = 1; + private static final int BEFORE_CODE = 2; + private static final int INSERTION_CODE = 3; + private static final int INVALID_CODE = 4; + private static final int SUBSTITUTION_CODE = 5; + private static final int DELETION_CODE = 6; + private static final int MERGE_CODE = 7; + private static final int MISPLACED_CODE = 8; + private static final int SCOPE_CODE = 9; + private static final int SECONDARY_CODE = 10; + private static final int EOF_CODE = 11; + + private static final int BUFF_UBOUND = 31; + private static final int BUFF_SIZE = 32; + private static final int MAX_DISTANCE = 30; + private static final int MIN_DISTANCE = 3; + + private LexStream lexStream; + private int errorToken; + private int errorTokenStart; + + private int currentToken = 0; + + private int stackLength; + private int stateStackTop; + private int[] stack; + + private int[] locationStack; + private int[] locationStartStack; + + private int tempStackTop; + private int[] tempStack; + + private int prevStackTop; + private int[] prevStack; + private int nextStackTop; + private int[] nextStack; + + private int scopeStackTop; + private int[] scopeIndex; + private int[] scopePosition; + + int[] list = new int[NUM_SYMBOLS + 1]; + int[] buffer = new int[BUFF_SIZE]; + + private static final int NIL = -1; + int[] stateSeen; + + int statePoolTop; + StateInfo[] statePool; + + private Parser parser; + + private class RepairCandidate { + public int symbol; + public int location; + + public RepairCandidate(){ + this.symbol = 0; + this.location = 0; + } + } + + private class PrimaryRepairInfo { + public int distance; + public int misspellIndex; + public int code; + public int bufferPosition; + public int symbol; + + public PrimaryRepairInfo(){ + this.distance = 0; + this.misspellIndex = 0; + this.code = 0; + this.bufferPosition = 0; + this.symbol = 0; + } + + public PrimaryRepairInfo copy(){ + PrimaryRepairInfo c = new PrimaryRepairInfo(); + c.distance = this.distance; + c.misspellIndex = this.misspellIndex; + c.code = this.code; + c.bufferPosition = this .bufferPosition; + c.symbol = this.symbol; + return c; + + } + } + + private class SecondaryRepairInfo { + public int code; + public int distance; + public int bufferPosition; + public int stackPosition; + public int numDeletions; + public int symbol; + + boolean recoveryOnNextStack; + } + + private class StateInfo { + int state; + int next; + + public StateInfo(int state, int next){ + this.state = state; + this.next = next; + } + } + + public DiagnoseParser(Parser parser, int firstToken, int start, int end) { + this(parser, firstToken, start, end, new int[0], new int[0], new int[0]); + } + + public DiagnoseParser(Parser parser, int firstToken, int start, int end, int[] intervalStartToSkip, int[] intervalEndToSkip, int[] intervalFlagsToSkip) { + this.parser = parser; + this.lexStream = new LexStream(BUFF_SIZE, parser.scanner, intervalStartToSkip, intervalEndToSkip, intervalFlagsToSkip, firstToken, start, end); + } + + private ProblemReporter problemReporter(){ + return parser.problemReporter(); + } + + private void reallocateStacks() { + int old_stack_length = stackLength; + + stackLength += STACK_INCREMENT; + + if(old_stack_length == 0){ + stack = new int[stackLength]; + locationStack = new int[stackLength]; + locationStartStack = new int[stackLength]; + tempStack = new int[stackLength]; + prevStack = new int[stackLength]; + nextStack = new int[stackLength]; + scopeIndex = new int[stackLength]; + scopePosition = new int[stackLength]; + } else { + System.arraycopy(stack, 0, stack = new int[stackLength], 0, old_stack_length); + System.arraycopy(locationStack, 0, locationStack = new int[stackLength], 0, old_stack_length); + System.arraycopy(locationStartStack, 0, locationStartStack = new int[stackLength], 0, old_stack_length); + System.arraycopy(tempStack, 0, tempStack = new int[stackLength], 0, old_stack_length); + System.arraycopy(prevStack, 0, prevStack = new int[stackLength], 0, old_stack_length); + System.arraycopy(nextStack, 0, nextStack = new int[stackLength], 0, old_stack_length); + System.arraycopy(scopeIndex, 0, scopeIndex = new int[stackLength], 0, old_stack_length); + System.arraycopy(scopePosition, 0, scopePosition = new int[stackLength], 0, old_stack_length); + } + return; + } + + + public void diagnoseParse() { + lexStream.reset(); + + currentToken = lexStream.getToken(); + + int prev_pos; + int pos; + int next_pos; + int act = START_STATE; + + reallocateStacks(); + + // + // Start parsing + // + stateStackTop = 0; + stack[stateStackTop] = act; + + int tok = lexStream.kind(currentToken); + locationStack[stateStackTop] = currentToken; + locationStartStack[stateStackTop] = lexStream.start(currentToken); + + boolean forceRecoveryAfterLBracketMissing = false; +// int forceRecoveryToken = -1; + + // + // Process a terminal + // + do { + // + // Synchronize state stacks and update the location stack + // + prev_pos = -1; + prevStackTop = -1; + + next_pos = -1; + nextStackTop = -1; + + pos = stateStackTop; + tempStackTop = stateStackTop - 1; + for (int i = 0; i <= stateStackTop; i++) + tempStack[i] = stack[i]; + + act = Parser.tAction(act, tok); + // + // When a reduce action is encountered, we compute all REDUCE + // and associated goto actions induced by the current token. + // Eventually, a SHIFT, SHIFT-REDUCE, ACCEPT or ERROR action is + // computed... + // + while (act <= NUM_RULES) { + do { + tempStackTop -= (Parser.rhs[act]-1); + act = Parser.ntAction(tempStack[tempStackTop], Parser.lhs[act]); + } while(act <= NUM_RULES); + // + // ... Update the maximum useful position of the + // (STATE_)STACK, push goto state into stack, and + // compute next action on current symbol ... + // + if (tempStackTop + 1 >= stackLength) + reallocateStacks(); + pos = pos < tempStackTop ? pos : tempStackTop; + tempStack[tempStackTop + 1] = act; + act = Parser.tAction(act, tok); + } + + // + // At this point, we have a shift, shift-reduce, accept or error + // action. STACK contains the configuration of the state stack + // prior to executing any action on curtok. next_stack contains + // the configuration of the state stack after executing all + // reduce actions induced by curtok. The variable pos indicates + // the highest position in STACK that is still useful after the + // reductions are executed. + // + while(act > ERROR_ACTION || act < ACCEPT_ACTION) { // SHIFT-REDUCE action or SHIFT action ? + nextStackTop = tempStackTop + 1; + for (int i = next_pos + 1; i <= nextStackTop; i++) + nextStack[i] = tempStack[i]; + + for (int i = pos + 1; i <= nextStackTop; i++) { + locationStack[i] = locationStack[stateStackTop]; + locationStartStack[i] = locationStartStack[stateStackTop]; + } + + // + // If we have a shift-reduce, process it as well as + // the goto-reduce actions that follow it. + // + if (act > ERROR_ACTION) { + act -= ERROR_ACTION; + do { + nextStackTop -= (Parser.rhs[act]-1); + act = Parser.ntAction(nextStack[nextStackTop], Parser.lhs[act]); + } while(act <= NUM_RULES); + pos = pos < nextStackTop ? pos : nextStackTop; + } + + if (nextStackTop + 1 >= stackLength) + reallocateStacks(); + + tempStackTop = nextStackTop; + nextStack[++nextStackTop] = act; + next_pos = nextStackTop; + + // + // Simulate the parser through the next token without + // destroying STACK or next_stack. + // + currentToken = lexStream.getToken(); + tok = lexStream.kind(currentToken); + act = Parser.tAction(act, tok); + while(act <= NUM_RULES) { + // + // ... Process all goto-reduce actions following + // reduction, until a goto action is computed ... + // + do { + int lhs_symbol = Parser.lhs[act]; + if(DEBUG) { + System.out.println(Parser.name[Parser.non_terminal_index[lhs_symbol]]); + } + tempStackTop -= (Parser.rhs[act]-1); + act = (tempStackTop > next_pos + ? tempStack[tempStackTop] + : nextStack[tempStackTop]); + act = Parser.ntAction(act, lhs_symbol); + } while(act <= NUM_RULES); + + // + // ... Update the maximum useful position of the + // (STATE_)STACK, push GOTO state into stack, and + // compute next action on current symbol ... + // + if (tempStackTop + 1 >= stackLength) + reallocateStacks(); + + next_pos = next_pos < tempStackTop ? next_pos : tempStackTop; + tempStack[tempStackTop + 1] = act; + act = Parser.tAction(act, tok); + } + +// if((tok != TokenNameRBRACE || (forceRecoveryToken != currentToken && (lexStream.flags(currentToken) & LexStream.LBRACE_MISSING) != 0)) +// && (lexStream.flags(currentToken) & LexStream.IS_AFTER_JUMP) !=0) { +// act = ERROR_ACTION; +// if(forceRecoveryToken != currentToken +// && (lexStream.flags(currentToken) & LexStream.LBRACE_MISSING) != 0) { +// forceRecoveryAfterLBracketMissing = true; +// forceRecoveryToken = currentToken; +// } +// } + + // + // No error was detected, Read next token into + // PREVTOK element, advance CURTOK pointer and + // update stacks. + // + if (act != ERROR_ACTION) { + prevStackTop = stateStackTop; + for (int i = prev_pos + 1; i <= prevStackTop; i++) + prevStack[i] = stack[i]; + prev_pos = pos; + + stateStackTop = nextStackTop; + for (int i = pos + 1; i <= stateStackTop; i++) + stack[i] = nextStack[i]; + locationStack[stateStackTop] = currentToken; + locationStartStack[stateStackTop] = lexStream.start(currentToken); + pos = next_pos; + } + } + + // + // At this stage, either we have an ACCEPT or an ERROR + // action. + // + if (act == ERROR_ACTION) { + // + // An error was detected. + // + RepairCandidate candidate = errorRecovery(currentToken, forceRecoveryAfterLBracketMissing); + + forceRecoveryAfterLBracketMissing = false; + + if(parser.reportOnlyOneSyntaxError) { + return; + } + + if(this.parser.problemReporter().options.maxProblemsPerUnit < this.parser.compilationUnit.compilationResult.problemCount) { + return; + } + + act = stack[stateStackTop]; + + // + // If the recovery was successful on a nonterminal candidate, + // parse through that candidate and "read" the next token. + // + if (candidate.symbol == 0) { + break; + } else if (candidate.symbol > NT_OFFSET) { + int lhs_symbol = candidate.symbol - NT_OFFSET; + if(DEBUG) { + System.out.println(Parser.name[Parser.non_terminal_index[lhs_symbol]]); + } + act = Parser.ntAction(act, lhs_symbol); + while(act <= NUM_RULES) { + stateStackTop -= (Parser.rhs[act]-1); + act = Parser.ntAction(stack[stateStackTop], Parser.lhs[act]); + } + stack[++stateStackTop] = act; + currentToken = lexStream.getToken(); + tok = lexStream.kind(currentToken); + locationStack[stateStackTop] = currentToken; + locationStartStack[stateStackTop] = lexStream.start(currentToken); + } else { + tok = candidate.symbol; + locationStack[stateStackTop] = candidate.location; + locationStartStack[stateStackTop] = lexStream.start(candidate.location); + } + } + } while (act != ACCEPT_ACTION); + + return; + } + + // +// This routine is invoked when an error is encountered. It +// tries to diagnose the error and recover from it. If it is +// successful, the state stack, the current token and the buffer +// are readjusted; i.e., after a successful recovery, +// state_stack_top points to the location in the state stack +// that contains the state on which to recover; curtok +// identifies the symbol on which to recover. +// +// Up to three configurations may be available when this routine +// is invoked. PREV_STACK may contain the sequence of states +// preceding any action on prevtok, STACK always contains the +// sequence of states preceding any action on curtok, and +// NEXT_STACK may contain the sequence of states preceding any +// action on the successor of curtok. +// + private RepairCandidate errorRecovery(int error_token, boolean forcedError) { + this.errorToken = error_token; + this.errorTokenStart = lexStream.start(error_token); + + int prevtok = lexStream.previous(error_token); + int prevtokKind = lexStream.kind(prevtok); + + if(forcedError) { + int name_index = Parser.terminal_index[TokenNameLBRACE]; + + reportError(INSERTION_CODE, name_index, prevtok, prevtok); + + RepairCandidate candidate = new RepairCandidate(); + candidate.symbol = TokenNameLBRACE; + candidate.location = error_token; + lexStream.reset(error_token); + + stateStackTop = nextStackTop; + for (int j = 0; j <= stateStackTop; j++) { + stack[j] = nextStack[j]; + } + locationStack[stateStackTop] = error_token; + locationStartStack[stateStackTop] = lexStream.start(error_token); + + return candidate; + } + + // + // Try primary phase recoveries. If not successful, try secondary + // phase recoveries. If not successful and we are at end of the + // file, we issue the end-of-file error and quit. Otherwise, ... + // + RepairCandidate candidate = primaryPhase(error_token); + if (candidate.symbol != 0) { + return candidate; + } + + candidate = secondaryPhase(error_token); + if (candidate.symbol != 0) { + return candidate; + } + + if (lexStream.kind(error_token) == EOFT_SYMBOL) { + reportError(EOF_CODE, + Parser.terminal_index[EOFT_SYMBOL], + prevtok, + prevtok); + candidate.symbol = 0; + candidate.location = error_token; + return candidate; + } + + // + // At this point, primary and (initial attempt at) secondary + // recovery did not work. We will now get into "panic mode" and + // keep trying secondary phase recoveries until we either find + // a successful recovery or have consumed the remaining input + // tokens. + // + while(lexStream.kind(buffer[BUFF_UBOUND]) != EOFT_SYMBOL) { + candidate = secondaryPhase(buffer[MAX_DISTANCE - MIN_DISTANCE + 2]); + if (candidate.symbol != 0) { + return candidate; + } + } + + // + // We reached the end of the file while panicking. Delete all + // remaining tokens in the input. + // + int i; + for (i = BUFF_UBOUND; lexStream.kind(buffer[i]) == EOFT_SYMBOL; i--){/*empty*/} + + reportError(DELETION_CODE, + Parser.terminal_index[prevtokKind],//Parser.terminal_index[lexStream.kind(prevtok)], + error_token, + buffer[i]); + + candidate.symbol = 0; + candidate.location = buffer[i]; + + return candidate; + } + +// +// This function tries primary and scope recovery on each +// available configuration. If a successful recovery is found +// and no secondary phase recovery can do better, a diagnosis is +// issued, the configuration is updated and the function returns +// "true". Otherwise, it returns "false". +// + private RepairCandidate primaryPhase(int error_token) { + PrimaryRepairInfo repair = new PrimaryRepairInfo(); + RepairCandidate candidate = new RepairCandidate(); + + // + // Initialize the buffer. + // + int i = (nextStackTop >= 0 ? 3 : 2); + buffer[i] = error_token; + + for (int j = i; j > 0; j--) + buffer[j - 1] = lexStream.previous(buffer[j]); + + for (int k = i + 1; k < BUFF_SIZE; k++) + buffer[k] = lexStream.next(buffer[k - 1]); + + // + // If NEXT_STACK_TOP > 0 then the parse was successful on CURTOK + // and the error was detected on the successor of CURTOK. In + // that case, first check whether or not primary recovery is + // possible on next_stack ... + // + if (nextStackTop >= 0) { + repair.bufferPosition = 3; + repair = checkPrimaryDistance(nextStack, nextStackTop, repair); + } + + // + // ... Next, try primary recovery on the current token... + // + PrimaryRepairInfo new_repair = repair.copy(); + + new_repair.bufferPosition = 2; + new_repair = checkPrimaryDistance(stack, stateStackTop, new_repair); + if (new_repair.distance > repair.distance || new_repair.misspellIndex > repair.misspellIndex) { + repair = new_repair; + } + + // + // Finally, if prev_stack_top >= 0 then try primary recovery on + // the prev_stack configuration. + // + + if (prevStackTop >= 0) { + new_repair = repair.copy(); + new_repair.bufferPosition = 1; + new_repair = checkPrimaryDistance(prevStack,prevStackTop, new_repair); + if (new_repair.distance > repair.distance || new_repair.misspellIndex > repair.misspellIndex) { + repair = new_repair; + } + } + + // + // Before accepting the best primary phase recovery obtained, + // ensure that we cannot do better with a similar secondary + // phase recovery. + // + if (nextStackTop >= 0) {// next_stack available + if (secondaryCheck(nextStack,nextStackTop,3,repair.distance)) { + return candidate; + } + } + else if (secondaryCheck(stack, stateStackTop, 2, repair.distance)) { + return candidate; + } + + // + // First, adjust distance if the recovery is on the error token; + // it is important that the adjustment be made here and not at + // each primary trial to prevent the distance tests from being + // biased in favor of deferred recoveries which have access to + // more input tokens... + // + repair.distance = repair.distance - repair.bufferPosition + 1; + + // + // ...Next, adjust the distance if the recovery is a deletion or + // (some form of) substitution... + // + if (repair.code == INVALID_CODE || + repair.code == DELETION_CODE || + repair.code == SUBSTITUTION_CODE || + repair.code == MERGE_CODE) { + repair.distance--; + } + + // + // ... After adjustment, check if the most successful primary + // recovery can be applied. If not, continue with more radical + // recoveries... + // + if (repair.distance < MIN_DISTANCE) { + return candidate; + } + + // + // When processing an insertion error, if the token preceeding + // the error token is not available, we change the repair code + // into a BEFORE_CODE to instruct the reporting routine that it + // indicates that the repair symbol should be inserted before + // the error token. + // + if (repair.code == INSERTION_CODE) { + if (buffer[repair.bufferPosition - 1] == 0) { + repair.code = BEFORE_CODE; + } + } + + // + // Select the proper sequence of states on which to recover, + // update stack accordingly and call diagnostic routine. + // + if (repair.bufferPosition == 1) { + stateStackTop = prevStackTop; + for (int j = 0; j <= stateStackTop; j++) { + stack[j] = prevStack[j]; + } + } else if (nextStackTop >= 0 && repair.bufferPosition >= 3) { + stateStackTop = nextStackTop; + for (int j = 0; j <= stateStackTop; j++) { + stack[j] = nextStack[j]; + } + locationStack[stateStackTop] = buffer[3]; + locationStartStack[stateStackTop] = lexStream.start(buffer[3]); + } + + return primaryDiagnosis(repair); + } + + +// +// This function checks whether or not a given state has a +// candidate, whose string representaion is a merging of the two +// tokens at positions buffer_position and buffer_position+1 in +// the buffer. If so, it returns the candidate in question; +// otherwise it returns 0. +// + private int mergeCandidate(int state, int buffer_position) { + char[] name1 = lexStream.name(buffer[buffer_position]); + char[] name2 = lexStream.name(buffer[buffer_position + 1]); + + int len = name1.length + name2.length; + + char[] str = CharOperation.concat(name1, name2); + + for (int k = Parser.asi(state); Parser.asr[k] != 0; k++) { + int l = Parser.terminal_index[Parser.asr[k]]; + + if (len == Parser.name[l].length()) { + char[] name = Parser.name[l].toCharArray(); + + if (CharOperation.equals(str, name, false)) { + return Parser.asr[k]; + } + } + } + + return 0; + } + + +// +// This procedure takes as arguments a parsing configuration +// consisting of a state stack (stack and stack_top) and a fixed +// number of input tokens (starting at buffer_position) in the +// input BUFFER; and some reference arguments: repair_code, +// distance, misspell_index, candidate, and stack_position +// which it sets based on the best possible recovery that it +// finds in the given configuration. The effectiveness of a +// a repair is judged based on two criteria: +// +// 1) the number of tokens that can be parsed after the repair +// is applied: distance. +// 2) how close to perfection is the candidate that is chosen: +// misspell_index. +// When this procedure is entered, distance, misspell_index and +// repair_code are assumed to be initialized. +// + private PrimaryRepairInfo checkPrimaryDistance(int stck[], int stack_top, PrimaryRepairInfo repair) { + int i, j, k, next_state, max_pos, act, root, symbol, tok; + + // + // First, try scope and manual recovery. + // + PrimaryRepairInfo scope_repair = scopeTrial(stck, stack_top, repair.copy()); + if (scope_repair.distance > repair.distance) + repair = scope_repair; + + // + // Next, try merging the error token with its successor. + // + if(buffer[repair.bufferPosition] != 0 && buffer[repair.bufferPosition + 1] != 0) {// do not merge the first token + symbol = mergeCandidate(stck[stack_top], repair.bufferPosition); + if (symbol != 0) { + j = parseCheck(stck, stack_top, symbol, repair.bufferPosition+2); + if ((j > repair.distance) || (j == repair.distance && repair.misspellIndex < 10)) { + repair.misspellIndex = 10; + repair.symbol = symbol; + repair.distance = j; + repair.code = MERGE_CODE; + } + } + } + + // + // Next, try deletion of the error token. + // + j = parseCheck( + stck, + stack_top, + lexStream.kind(buffer[repair.bufferPosition + 1]), + repair.bufferPosition + 2); + if (lexStream.kind(buffer[repair.bufferPosition]) == EOLT_SYMBOL && + lexStream.afterEol(buffer[repair.bufferPosition+1])) { + k = 10; + } else { + k = 0; + } + if (j > repair.distance || (j == repair.distance && k > repair.misspellIndex)) { + repair.misspellIndex = k; + repair.code = DELETION_CODE; + repair.distance = j; + } + + // + // Update the error configuration by simulating all reduce and + // goto actions induced by the error token. Then assign the top + // most state of the new configuration to next_state. + // + next_state = stck[stack_top]; + max_pos = stack_top; + tempStackTop = stack_top - 1; + + tok = lexStream.kind(buffer[repair.bufferPosition]); + lexStream.reset(buffer[repair.bufferPosition + 1]); + act = Parser.tAction(next_state, tok); + while(act <= NUM_RULES) { + do { + tempStackTop -= (Parser.rhs[act]-1); + symbol = Parser.lhs[act]; + act = (tempStackTop > max_pos + ? tempStack[tempStackTop] + : stck[tempStackTop]); + act = Parser.ntAction(act, symbol); + } while(act <= NUM_RULES); + max_pos = max_pos < tempStackTop ? max_pos : tempStackTop; + tempStack[tempStackTop + 1] = act; + next_state = act; + act = Parser.tAction(next_state, tok); + } + + // + // Next, place the list of candidates in proper order. + // + root = 0; + for (i = Parser.asi(next_state); Parser.asr[i] != 0; i++) { + symbol = Parser.asr[i]; + if (symbol != EOFT_SYMBOL && symbol != ERROR_SYMBOL) { + if (root == 0) { + list[symbol] = symbol; + } else { + list[symbol] = list[root]; + list[root] = symbol; + } + root = symbol; + } + } + + if (stck[stack_top] != next_state) { + for (i = Parser.asi(stck[stack_top]); Parser.asr[i] != 0; i++) { + symbol = Parser.asr[i]; + if (symbol != EOFT_SYMBOL && symbol != ERROR_SYMBOL && list[symbol] == 0) { + if (root == 0) { + list[symbol] = symbol; + } else { + list[symbol] = list[root]; + list[root] = symbol; + } + root = symbol; + } + } + } + + i = list[root]; + list[root] = 0; + root = i; + + // + // Next, try insertion for each possible candidate available in + // the current state, except EOFT and ERROR_SYMBOL. + // + symbol = root; + while(symbol != 0) { + if (symbol == EOLT_SYMBOL && lexStream.afterEol(buffer[repair.bufferPosition])) { + k = 10; + } else { + k = 0; + } + j = parseCheck(stck, stack_top, symbol, repair.bufferPosition); + if (j > repair.distance) { + repair.misspellIndex = k; + repair.distance = j; + repair.symbol = symbol; + repair.code = INSERTION_CODE; + } else if (j == repair.distance && k > repair.misspellIndex) { + repair.misspellIndex = k; + repair.distance = j; + repair.symbol = symbol; + repair.code = INSERTION_CODE; + } else if (j == repair.distance && k == repair.misspellIndex && isBetterSymbol(symbol, repair.symbol)) { + repair.misspellIndex = k; + repair.distance = j; + repair.symbol = symbol; + repair.code = INSERTION_CODE; + } + + symbol = list[symbol]; + } + + // + // Next, Try substitution for each possible candidate available + // in the current state, except EOFT and ERROR_SYMBOL. + // + symbol = root; + + if(buffer[repair.bufferPosition] != 0) {// do not replace the first token + while(symbol != 0) { + if (symbol == EOLT_SYMBOL && lexStream.afterEol(buffer[repair.bufferPosition+1])) { + k = 10; + } else { + k = misspell(symbol, buffer[repair.bufferPosition]); + } + j = parseCheck(stck, stack_top, symbol, repair.bufferPosition+1); + if (j > repair.distance) { + repair.misspellIndex = k; + repair.distance = j; + repair.symbol = symbol; + repair.code = SUBSTITUTION_CODE; + } else if (j == repair.distance && k > repair.misspellIndex) { + repair.misspellIndex = k; + repair.symbol = symbol; + repair.code = SUBSTITUTION_CODE; + } else if (j == repair.distance && k > repair.misspellIndex && isBetterSymbol(symbol, repair.symbol)) { + repair.misspellIndex = k; + repair.symbol = symbol; + repair.code = SUBSTITUTION_CODE; + } + i = symbol; + symbol = list[symbol]; + list[i] = 0; // reset element + } + } + + + // + // Next, we try to insert a nonterminal candidate in front of the + // error token, or substituting a nonterminal candidate for the + // error token. Precedence is given to insertion. + // + for (i = Parser.nasi(stck[stack_top]); Parser.nasr[i] != 0; i++) { + symbol = Parser.nasr[i] + NT_OFFSET; + j = parseCheck(stck, stack_top, symbol, repair.bufferPosition+1); + if (j > repair.distance) { + repair.misspellIndex = 0; + repair.distance = j; + repair.symbol = symbol; + repair.code = INVALID_CODE; + } + + j = parseCheck(stck, stack_top, symbol, repair.bufferPosition); + if ((j > repair.distance) || (j == repair.distance && repair.code == INVALID_CODE)) { + repair.misspellIndex = 0; + repair.distance = j; + repair.symbol = symbol; + repair.code = INSERTION_CODE; + } + } + + return repair; + } + + +// +// This procedure is invoked to issue a diagnostic message and +// adjust the input buffer. The recovery in question is either +// the insertion of one or more scopes, the merging of the error +// token with its successor, the deletion of the error token, +// the insertion of a single token in front of the error token +// or the substitution of another token for the error token. +// + private RepairCandidate primaryDiagnosis(PrimaryRepairInfo repair) { + int name_index; + + // + // Issue diagnostic. + // + int prevtok = buffer[repair.bufferPosition - 1]; + int curtok = buffer[repair.bufferPosition]; + + switch(repair.code) { + case INSERTION_CODE: + case BEFORE_CODE: { + if (repair.symbol > NT_OFFSET) + name_index = getNtermIndex(stack[stateStackTop], + repair.symbol, + repair.bufferPosition); + else name_index = getTermIndex(stack, + stateStackTop, + repair.symbol, + repair.bufferPosition); + + int t = (repair.code == INSERTION_CODE ? prevtok : curtok); + reportError(repair.code, name_index, t, t); + break; + } + case INVALID_CODE: { + name_index = getNtermIndex(stack[stateStackTop], + repair.symbol, + repair.bufferPosition + 1); + reportError(repair.code, name_index, curtok, curtok); + break; + } + case SUBSTITUTION_CODE: { + if (repair.misspellIndex >= 6) + name_index = Parser.terminal_index[repair.symbol]; + else + { + name_index = getTermIndex(stack, stateStackTop, + repair.symbol, + repair.bufferPosition + 1); + if (name_index != Parser.terminal_index[repair.symbol]) + repair.code = INVALID_CODE; + } + reportError(repair.code, name_index, curtok, curtok); + break; + } + case MERGE_CODE: { + reportError(repair.code, + Parser.terminal_index[repair.symbol], + curtok, + lexStream.next(curtok)); + break; + } + case SCOPE_CODE: { + for (int i = 0; i < scopeStackTop; i++) { + reportError(repair.code, + -scopeIndex[i], + locationStack[scopePosition[i]], + prevtok, + Parser.non_terminal_index[Parser.scope_lhs[scopeIndex[i]]]); + } + + repair.symbol = Parser.scope_lhs[scopeIndex[scopeStackTop]] + NT_OFFSET; + stateStackTop = scopePosition[scopeStackTop]; + reportError(repair.code, + -scopeIndex[scopeStackTop], + locationStack[scopePosition[scopeStackTop]], + prevtok, + getNtermIndex(stack[stateStackTop], + repair.symbol, + repair.bufferPosition) + ); + break; + } + default: {// deletion + reportError(repair.code, Parser.terminal_index[ERROR_SYMBOL], curtok, curtok); + } + } + + // + // Update buffer. + // + RepairCandidate candidate = new RepairCandidate(); + switch (repair.code) { + case INSERTION_CODE: + case BEFORE_CODE: + case SCOPE_CODE: { + candidate.symbol = repair.symbol; + candidate.location = buffer[repair.bufferPosition]; + lexStream.reset(buffer[repair.bufferPosition]); + break; + } + case INVALID_CODE: + case SUBSTITUTION_CODE: { + candidate.symbol = repair.symbol; + candidate.location = buffer[repair.bufferPosition]; + lexStream.reset(buffer[repair.bufferPosition + 1]); + break; + } + case MERGE_CODE: { + candidate.symbol = repair.symbol; + candidate.location = buffer[repair.bufferPosition]; + lexStream.reset(buffer[repair.bufferPosition + 2]); + break; + } + default: {// deletion + candidate.location = buffer[repair.bufferPosition + 1]; + candidate.symbol = + lexStream.kind(buffer[repair.bufferPosition + 1]); + lexStream.reset(buffer[repair.bufferPosition + 2]); + break; + } + } + + return candidate; + } + + +// +// This function takes as parameter an integer STACK_TOP that +// points to a STACK element containing the state on which a +// primary recovery will be made; the terminal candidate on which +// to recover; and an integer: buffer_position, which points to +// the position of the next input token in the BUFFER. The +// parser is simulated until a shift (or shift-reduce) action +// is computed on the candidate. Then we proceed to compute the +// the name index of the highest level nonterminal that can +// directly or indirectly produce the candidate. +// + private int getTermIndex(int stck[], int stack_top, int tok, int buffer_position) { + // + // Initialize stack index of temp_stack and initialize maximum + // position of state stack that is still useful. + // + int act = stck[stack_top], + max_pos = stack_top, + highest_symbol = tok; + + tempStackTop = stack_top - 1; + + // + // Compute all reduce and associated actions induced by the + // candidate until a SHIFT or SHIFT-REDUCE is computed. ERROR + // and ACCEPT actions cannot be computed on the candidate in + // this context, since we know that it is suitable for recovery. + // + lexStream.reset(buffer[buffer_position]); + act = Parser.tAction(act, tok); + while(act <= NUM_RULES) { + // + // Process all goto-reduce actions following reduction, + // until a goto action is computed ... + // + do { + tempStackTop -= (Parser.rhs[act]-1); + int lhs_symbol = Parser.lhs[act]; + act = (tempStackTop > max_pos + ? tempStack[tempStackTop] + : stck[tempStackTop]); + act = Parser.ntAction(act, lhs_symbol); + } while(act <= NUM_RULES); + + // + // Compute new maximum useful position of (STATE_)stack, + // push goto state into the stack, and compute next + // action on candidate ... + // + max_pos = max_pos < tempStackTop ? max_pos : tempStackTop; + tempStack[tempStackTop + 1] = act; + act = Parser.tAction(act, tok); + } + + // + // At this stage, we have simulated all actions induced by the + // candidate and we are ready to shift or shift-reduce it. First, + // set tok and next_ptr appropriately and identify the candidate + // as the initial highest_symbol. If a shift action was computed + // on the candidate, update the stack and compute the next + // action. Next, simulate all actions possible on the next input + // token until we either have to shift it or are about to reduce + // below the initial starting point in the stack (indicated by + // max_pos as computed in the previous loop). At that point, + // return the highest_symbol computed. + // + tempStackTop++; // adjust top of stack to reflect last goto + // next move is shift or shift-reduce. + int threshold = tempStackTop; + + tok = lexStream.kind(buffer[buffer_position]); + lexStream.reset(buffer[buffer_position + 1]); + + if (act > ERROR_ACTION) { // shift-reduce on candidate? + act -= ERROR_ACTION; + } else { + tempStack[tempStackTop + 1] = act; + act = Parser.tAction(act, tok); + } + + while(act <= NUM_RULES) { + // + // Process all goto-reduce actions following reduction, + // until a goto action is computed ... + // + do { + tempStackTop -= (Parser.rhs[act]-1); + + if (tempStackTop < threshold) { + return (highest_symbol > NT_OFFSET + ? Parser.non_terminal_index[highest_symbol - NT_OFFSET] + : Parser.terminal_index[highest_symbol]); + } + + int lhs_symbol = Parser.lhs[act]; + if (tempStackTop == threshold) + highest_symbol = lhs_symbol + NT_OFFSET; + act = (tempStackTop > max_pos + ? tempStack[tempStackTop] + : stck[tempStackTop]); + act = Parser.ntAction(act, lhs_symbol); + } while(act <= NUM_RULES); + + tempStack[tempStackTop + 1] = act; + act = Parser.tAction(act, tok); + } + + return (highest_symbol > NT_OFFSET + ? Parser.non_terminal_index[highest_symbol - NT_OFFSET] + : Parser.terminal_index[highest_symbol]); + } + +// +// This function takes as parameter a starting state number: +// start, a nonterminal symbol, A (candidate), and an integer, +// buffer_position, which points to the position of the next +// input token in the BUFFER. +// It returns the highest level non-terminal B such that +// B =>*rm A. I.e., there does not exists a nonterminal C such +// that C =>+rm B. (Recall that for an LALR(k) grammar if +// C =>+rm B, it cannot be the case that B =>+rm C) +// + private int getNtermIndex(int start, int sym, int buffer_position) { + int highest_symbol = sym - NT_OFFSET, + tok = lexStream.kind(buffer[buffer_position]); + lexStream.reset(buffer[buffer_position + 1]); + + // + // Initialize stack index of temp_stack and initialize maximum + // position of state stack that is still useful. + // + tempStackTop = 0; + tempStack[tempStackTop] = start; + + int act = Parser.ntAction(start, highest_symbol); + if (act > NUM_RULES) { // goto action? + tempStack[tempStackTop + 1] = act; + act = Parser.tAction(act, tok); + } + + while(act <= NUM_RULES) { + // + // Process all goto-reduce actions following reduction, + // until a goto action is computed ... + // + do { + tempStackTop -= (Parser.rhs[act]-1); + if (tempStackTop < 0) + return Parser.non_terminal_index[highest_symbol]; + if (tempStackTop == 0) + highest_symbol = Parser.lhs[act]; + act = Parser.ntAction(tempStack[tempStackTop], Parser.lhs[act]); + } while(act <= NUM_RULES); + tempStack[tempStackTop + 1] = act; + act = Parser.tAction(act, tok); + } + + return Parser.non_terminal_index[highest_symbol]; + } + + private boolean isBetterSymbol(int symbol, int actualSymbol) { +// switch (actualSymbol) { +// case TokenNameinterface : +// if(symbol == TokenNameclass) { +// return true; +// } +// break; +// } + return false; + } + +// +// Check whether or not there is a high probability that a +// given string is a misspelling of another. +// Certain singleton symbols (such as ":" and ";") are also +// considered to be misspelling of each other. +// + private int misspell(int sym, int tok) { + + + // + // + // + char[] name = Parser.name[Parser.terminal_index[sym]].toCharArray(); + int n = name.length; + char[] s1 = new char[n + 1]; + for (int k = 0; k < n; k++) { + char c = name[k]; + s1[k] = Character.toLowerCase(c); + } + s1[n] = '\0'; + + // + // + // + char[] tokenName = lexStream.name(tok); + int len = tokenName.length; + int m = len < MAX_NAME_LENGTH ? len : MAX_NAME_LENGTH; + char[] s2 = new char[m + 1]; + for (int k = 0; k < m; k++) { + char c = tokenName[k]; + s2[k] = Character.toLowerCase(c); + } + s2[m] = '\0'; + + // + // Singleton mispellings: + // + // ; <----> , + // + // ; <----> : + // + // . <----> , + // + // ' <----> " + // + // + if (n == 1 && m == 1) { + if ((s1[0] == ';' && s2[0] == ',') || + (s1[0] == ',' && s2[0] == ';') || + (s1[0] == ';' && s2[0] == ':') || + (s1[0] == ':' && s2[0] == ';') || + (s1[0] == '.' && s2[0] == ',') || + (s1[0] == ',' && s2[0] == '.') || + (s1[0] == '\'' && s2[0] == '\"') || + (s1[0] == '\"' && s2[0] == '\'')) { + return 3; + } + } + + // + // Scan the two strings. Increment "match" count for each match. + // When a transposition is encountered, increase "match" count + // by two but count it as an error. When a typo is found, skip + // it and count it as an error. Otherwise we have a mismatch; if + // one of the strings is longer, increment its index, otherwise, + // increment both indices and continue. + // + // This algorithm is an adaptation of a boolean misspelling + // algorithm proposed by Juergen Uhl. + // + int count = 0; + int prefix_length = 0; + int num_errors = 0; + + int i = 0; + int j = 0; + while ((i < n) && (j < m)) { + if (s1[i] == s2[j]) { + count++; + i++; + j++; + if (num_errors == 0) { + prefix_length++; + } + } else if (s1[i+1] == s2[j] && s1[i] == s2[j+1]) { + count += 2; + i += 2; + j += 2; + num_errors++; + } else if (s1[i+1] == s2[j+1]) { + i++; + j++; + num_errors++; + } else { + if ((n - i) > (m - j)) { + i++; + } else if ((m - j) > (n - i)) { + j++; + } else { + i++; + j++; + } + num_errors++; + } + } + + if (i < n || j < m) + num_errors++; + + if (num_errors > ((n < m ? n : m) / 6 + 1)) + count = prefix_length; + + return(count * 10 / ((n < len ? len : n) + num_errors)); + } + + private PrimaryRepairInfo scopeTrial(int stck[], int stack_top, PrimaryRepairInfo repair) { + stateSeen = new int[stackLength]; + for (int i = 0; i < stackLength; i++) + stateSeen[i] = NIL; + + statePoolTop = 0; + statePool = new StateInfo[stackLength]; + + scopeTrialCheck(stck, stack_top, repair, 0); + + stateSeen = null; + statePoolTop = 0; + + repair.code = SCOPE_CODE; + repair.misspellIndex = 10; + + return repair; + } + + private void scopeTrialCheck(int stck[], int stack_top, PrimaryRepairInfo repair, int indx) { + if(indx > 20) return; // avoid too much recursive call to improve performance + + int act = stck[stack_top]; + + for (int i = stateSeen[stack_top]; i != NIL; i = statePool[i].next) { + if (statePool[i].state == act) return; + } + + int old_state_pool_top = statePoolTop++; + if(statePoolTop >= statePool.length) { + System.arraycopy(statePool, 0, statePool = new StateInfo[statePoolTop * 2], 0, statePoolTop); + } + + statePool[old_state_pool_top] = new StateInfo(act, stateSeen[stack_top]); + stateSeen[stack_top] = old_state_pool_top; + + for (int i = 0; i < SCOPE_SIZE; i++) { + // + // Use the scope lookahead symbol to force all reductions + // inducible by that symbol. + // + act = stck[stack_top]; + tempStackTop = stack_top - 1; + int max_pos = stack_top; + int tok = Parser.scope_la[i]; + lexStream.reset(buffer[repair.bufferPosition]); + act = Parser.tAction(act, tok); + while(act <= NUM_RULES) { + // + // ... Process all goto-reduce actions following + // reduction, until a goto action is computed ... + // + do { + tempStackTop -= (Parser.rhs[act]-1); + int lhs_symbol = Parser.lhs[act]; + act = (tempStackTop > max_pos + ? tempStack[tempStackTop] + : stck[tempStackTop]); + act = Parser.ntAction(act, lhs_symbol); + } while(act <= NUM_RULES); + if (tempStackTop + 1 >= stackLength) + return; + max_pos = max_pos < tempStackTop ? max_pos : tempStackTop; + tempStack[tempStackTop + 1] = act; + act = Parser.tAction(act, tok); + } + + // + // If the lookahead symbol is parsable, then we check + // whether or not we have a match between the scope + // prefix and the transition symbols corresponding to + // the states on top of the stack. + // + if (act != ERROR_ACTION) { + int j, k; + k = Parser.scope_prefix[i]; + for (j = tempStackTop + 1; + j >= (max_pos + 1) && + Parser.in_symbol(tempStack[j]) == Parser.scope_rhs[k]; j--) { + k++; + } + if (j == max_pos) { + for (j = max_pos; + j >= 1 && Parser.in_symbol(stck[j]) == Parser.scope_rhs[k]; + j--) { + k++; + } + } + // + // If the prefix matches, check whether the state + // newly exposed on top of the stack, (after the + // corresponding prefix states are popped from the + // stack), is in the set of "source states" for the + // scope in question and that it is at a position + // below the threshold indicated by MARKED_POS. + // + int marked_pos = (max_pos < stack_top ? max_pos + 1 : stack_top); + if (Parser.scope_rhs[k] == 0 && j < marked_pos) { // match? + int stack_position = j; + for (j = Parser.scope_state_set[i]; + stck[stack_position] != Parser.scope_state[j] && + Parser.scope_state[j] != 0; + j++){/*empty*/} + // + // If the top state is valid for scope recovery, + // the left-hand side of the scope is used as + // starting symbol and we calculate how far the + // parser can advance within the forward context + // after parsing the left-hand symbol. + // + if (Parser.scope_state[j] != 0) { // state was found + int previous_distance = repair.distance; + int distance = parseCheck(stck, + stack_position, + Parser.scope_lhs[i]+NT_OFFSET, + repair.bufferPosition); + // + // if the recovery is not successful, we + // update the stack with all actions induced + // by the left-hand symbol, and recursively + // call SCOPE_TRIAL_CHECK to try again. + // Otherwise, the recovery is successful. If + // the new distance is greater than the + // initial SCOPE_DISTANCE, we update + // SCOPE_DISTANCE and set scope_stack_top to INDX + // to indicate the number of scopes that are + // to be applied for a succesful recovery. + // NOTE that this procedure cannot get into + // an infinite loop, since each prefix match + // is guaranteed to take us to a lower point + // within the stack. + // + if ((distance - repair.bufferPosition + 1) < MIN_DISTANCE) { + int top = stack_position; + act = Parser.ntAction(stck[top], Parser.scope_lhs[i]); + while(act <= NUM_RULES) { + top -= (Parser.rhs[act]-1); + act = Parser.ntAction(stck[top], Parser.lhs[act]); + } + top++; + + j = act; + act = stck[top]; // save + stck[top] = j; // swap + scopeTrialCheck(stck, top, repair, indx+1); + stck[top] = act; // restore + } else if (distance > repair.distance) { + scopeStackTop = indx; + repair.distance = distance; + } + + if (lexStream.kind(buffer[repair.bufferPosition]) == EOFT_SYMBOL && + repair.distance == previous_distance) { + scopeStackTop = indx; + repair.distance = MAX_DISTANCE; + } + + // + // If this scope recovery has beaten the + // previous distance, then we have found a + // better recovery (or this recovery is one + // of a list of scope recoveries). Record + // its information at the proper location + // (INDX) in SCOPE_INDEX and SCOPE_STACK. + // + if (repair.distance > previous_distance) { + scopeIndex[indx] = i; + scopePosition[indx] = stack_position; + return; + } + } + } + } + } + } +// +// This function computes the ParseCheck distance for the best +// possible secondary recovery for a given configuration that +// either deletes none or only one symbol in the forward context. +// If the recovery found is more effective than the best primary +// recovery previously computed, then the function returns true. +// Only misplacement, scope and manual recoveries are attempted; +// simple insertion or substitution of a nonterminal are tried +// in CHECK_PRIMARY_DISTANCE as part of primary recovery. +// + private boolean secondaryCheck(int stck[], int stack_top, int buffer_position, int distance) { + int top, j; + + for (top = stack_top - 1; top >= 0; top--) { + j = parseCheck(stck, top, + lexStream.kind(buffer[buffer_position]), + buffer_position + 1); + if (((j - buffer_position + 1) > MIN_DISTANCE) && (j > distance)) + return true; + } + + PrimaryRepairInfo repair = new PrimaryRepairInfo(); + repair.bufferPosition = buffer_position + 1; + repair.distance = distance; + repair = scopeTrial(stck, stack_top, repair); + if ((repair.distance - buffer_position) > MIN_DISTANCE && repair.distance > distance) + return true; + return false; + } + + +// +// Secondary_phase is a boolean function that checks whether or +// not some form of secondary recovery is applicable to one of +// the error configurations. First, if "next_stack" is available, +// misplacement and secondary recoveries are attempted on it. +// Then, in any case, these recoveries are attempted on "stack". +// If a successful recovery is found, a diagnosis is issued, the +// configuration is updated and the function returns "true". +// Otherwise, the function returns false. +// + private RepairCandidate secondaryPhase(int error_token) { + SecondaryRepairInfo repair = new SecondaryRepairInfo(); + SecondaryRepairInfo misplaced = new SecondaryRepairInfo(); + + RepairCandidate candidate = new RepairCandidate(); + + int i, j, k, top; + int next_last_index = 0; + int last_index; + + candidate.symbol = 0; + + repair.code = 0; + repair.distance = 0; + repair.recoveryOnNextStack = false; + + misplaced.distance = 0; + misplaced.recoveryOnNextStack = false; + + // + // If the next_stack is available, try misplaced and secondary + // recovery on it first. + // + if (nextStackTop >= 0) { + int save_location; + + buffer[2] = error_token; + buffer[1] = lexStream.previous(buffer[2]); + buffer[0] = lexStream.previous(buffer[1]); + + for (k = 3; k < BUFF_UBOUND; k++) + buffer[k] = lexStream.next(buffer[k - 1]); + + buffer[BUFF_UBOUND] = lexStream.badtoken();// elmt not available + + // + // If we are at the end of the input stream, compute the + // index position of the first EOFT symbol (last useful + // index). + // + for (next_last_index = MAX_DISTANCE - 1; + next_last_index >= 1 && + lexStream.kind(buffer[next_last_index]) == EOFT_SYMBOL; + next_last_index--){/*empty*/} + next_last_index = next_last_index + 1; + + save_location = locationStack[nextStackTop]; + int save_location_start = locationStartStack[nextStackTop]; + locationStack[nextStackTop] = buffer[2]; + locationStartStack[nextStackTop] = lexStream.start(buffer[2]); + misplaced.numDeletions = nextStackTop; + misplaced = misplacementRecovery(nextStack, nextStackTop, + next_last_index, + misplaced, true); + if (misplaced.recoveryOnNextStack) + misplaced.distance++; + + repair.numDeletions = nextStackTop + BUFF_UBOUND; + repair = secondaryRecovery(nextStack, nextStackTop, + next_last_index, + repair, true); + if (repair.recoveryOnNextStack) + repair.distance++; + + locationStack[nextStackTop] = save_location; + locationStartStack[nextStackTop] = save_location_start; + } else { // next_stack not available, initialize ... + misplaced.numDeletions = stateStackTop; + repair.numDeletions = stateStackTop + BUFF_UBOUND; + } + + // + // Try secondary recovery on the "stack" configuration. + // + buffer[3] = error_token; + + buffer[2] = lexStream.previous(buffer[3]); + buffer[1] = lexStream.previous(buffer[2]); + buffer[0] = lexStream.previous(buffer[1]); + + for (k = 4; k < BUFF_SIZE; k++) + buffer[k] = lexStream.next(buffer[k - 1]); + + for (last_index = MAX_DISTANCE - 1; + last_index >= 1 && lexStream.kind(buffer[last_index]) == EOFT_SYMBOL; + last_index--){/*empty*/} + last_index++; + + misplaced = misplacementRecovery(stack, stateStackTop, + last_index, + misplaced, false); + + repair = secondaryRecovery(stack, stateStackTop, + last_index, repair, false); + + // + // If a successful misplaced recovery was found, compare it with + // the most successful secondary recovery. If the misplaced + // recovery either deletes fewer symbols or parse-checks further + // then it is chosen. + // + if (misplaced.distance > MIN_DISTANCE) { + if (misplaced.numDeletions <= repair.numDeletions || + (misplaced.distance - misplaced.numDeletions) >= + (repair.distance - repair.numDeletions)) { + repair.code = MISPLACED_CODE; + repair.stackPosition = misplaced.stackPosition; + repair.bufferPosition = 2; + repair.numDeletions = misplaced.numDeletions; + repair.distance = misplaced.distance; + repair.recoveryOnNextStack = misplaced.recoveryOnNextStack; + } + } + + // + // If the successful recovery was on next_stack, update: stack, + // buffer, location_stack and last_index. + // + if (repair.recoveryOnNextStack) { + stateStackTop = nextStackTop; + for (i = 0; i <= stateStackTop; i++) + stack[i] = nextStack[i]; + + buffer[2] = error_token; + buffer[1] = lexStream.previous(buffer[2]); + buffer[0] = lexStream.previous(buffer[1]); + + for (k = 3; k < BUFF_UBOUND; k++) + buffer[k] = lexStream.next(buffer[k - 1]); + + buffer[BUFF_UBOUND] = lexStream.badtoken();// elmt not available + + locationStack[nextStackTop] = buffer[2]; + locationStartStack[nextStackTop] = lexStream.start(buffer[2]); + last_index = next_last_index; + } + + // + // Next, try scope recoveries after deletion of one, two, three, + // four ... buffer_position tokens from the input stream. + // + if (repair.code == SECONDARY_CODE || repair.code == DELETION_CODE) { + PrimaryRepairInfo scope_repair = new PrimaryRepairInfo(); + + scope_repair.distance = 0; + for (scope_repair.bufferPosition = 2; + scope_repair.bufferPosition <= repair.bufferPosition && + repair.code != SCOPE_CODE; scope_repair.bufferPosition++) { + scope_repair = scopeTrial(stack, stateStackTop, scope_repair); + j = (scope_repair.distance == MAX_DISTANCE + ? last_index + : scope_repair.distance); + k = scope_repair.bufferPosition - 1; + if ((j - k) > MIN_DISTANCE && (j - k) > (repair.distance - repair.numDeletions)) { + repair.code = SCOPE_CODE; + i = scopeIndex[scopeStackTop]; // upper bound + repair.symbol = Parser.scope_lhs[i] + NT_OFFSET; + repair.stackPosition = stateStackTop; + repair.bufferPosition = scope_repair.bufferPosition; + } + } + } + + // + // If no successful recovery is found and we have reached the + // end of the file, check whether or not scope recovery is + // applicable at the end of the file after discarding some + // states. + // + if (repair.code == 0 && lexStream.kind(buffer[last_index]) == EOFT_SYMBOL) { + PrimaryRepairInfo scope_repair = new PrimaryRepairInfo(); + + scope_repair.bufferPosition = last_index; + scope_repair.distance = 0; + for (top = stateStackTop; + top >= 0 && repair.code == 0; top--) + { + scope_repair = scopeTrial(stack, top, scope_repair); + if (scope_repair.distance > 0) + { + repair.code = SCOPE_CODE; + i = scopeIndex[scopeStackTop]; // upper bound + repair.symbol = Parser.scope_lhs[i] + NT_OFFSET; + repair.stackPosition = top; + repair.bufferPosition = scope_repair.bufferPosition; + } + } + } + + // + // If a successful repair was not found, quit! Otherwise, issue + // diagnosis and adjust configuration... + // + if (repair.code == 0) + return candidate; + + secondaryDiagnosis(repair); + + // + // Update buffer based on number of elements that are deleted. + // + switch(repair.code) { + case MISPLACED_CODE: + candidate.location = buffer[2]; + candidate.symbol = lexStream.kind(buffer[2]); + lexStream.reset(lexStream.next(buffer[2])); + + break; + + case DELETION_CODE: + candidate.location = buffer[repair.bufferPosition]; + candidate.symbol = + lexStream.kind(buffer[repair.bufferPosition]); + lexStream.reset(lexStream.next(buffer[repair.bufferPosition])); + + break; + + default: // SCOPE_CODE || SECONDARY_CODE + candidate.symbol = repair.symbol; + candidate.location = buffer[repair.bufferPosition]; + lexStream.reset(buffer[repair.bufferPosition]); + + break; + } + + return candidate; + } + + +// +// This boolean function checks whether or not a given +// configuration yields a better misplacement recovery than +// the best misplacement recovery computed previously. +// + private SecondaryRepairInfo misplacementRecovery(int stck[], int stack_top, int last_index, SecondaryRepairInfo repair, boolean stack_flag) { + int previous_loc = buffer[2]; + int stack_deletions = 0; + + for (int top = stack_top - 1; top >= 0; top--) { + if (locationStack[top] < previous_loc) { + stack_deletions++; + } + previous_loc = locationStack[top]; + + int j = parseCheck(stck, top, lexStream.kind(buffer[2]), 3); + if (j == MAX_DISTANCE) { + j = last_index; + } + if ((j > MIN_DISTANCE) && (j - stack_deletions) > (repair.distance - repair.numDeletions)) { + repair.stackPosition = top; + repair.distance = j; + repair.numDeletions = stack_deletions; + repair.recoveryOnNextStack = stack_flag; + } + } + + return repair; + } + + +// +// This boolean function checks whether or not a given +// configuration yields a better secondary recovery than the +// best misplacement recovery computed previously. +// + private SecondaryRepairInfo secondaryRecovery(int stck[],int stack_top, int last_index, SecondaryRepairInfo repair, boolean stack_flag) { + int previous_loc; + int stack_deletions = 0; + + previous_loc = buffer[2]; + for (int top = stack_top; top >= 0 && repair.numDeletions >= stack_deletions; top--) { + if (locationStack[top] < previous_loc) { + stack_deletions++; + } + previous_loc = locationStack[top]; + + for (int i = 2; + i <= (last_index - MIN_DISTANCE + 1) && + (repair.numDeletions >= (stack_deletions + i - 1)); i++) { + int j = parseCheck(stck, top, lexStream.kind(buffer[i]), i + 1); + + if (j == MAX_DISTANCE) { + j = last_index; + } + if ((j - i + 1) > MIN_DISTANCE) { + int k = stack_deletions + i - 1; + if ((k < repair.numDeletions) || + (j - k) > (repair.distance - repair.numDeletions) || + ((repair.code == SECONDARY_CODE) && (j - k) == (repair.distance - repair.numDeletions))) { + repair.code = DELETION_CODE; + repair.distance = j; + repair.stackPosition = top; + repair.bufferPosition = i; + repair.numDeletions = k; + repair.recoveryOnNextStack = stack_flag; + } + } + + for (int l = Parser.nasi(stck[top]); l >= 0 && Parser.nasr[l] != 0; l++) { + int symbol = Parser.nasr[l] + NT_OFFSET; + j = parseCheck(stck, top, symbol, i); + if (j == MAX_DISTANCE) { + j = last_index; + } + if ((j - i + 1) > MIN_DISTANCE) { + int k = stack_deletions + i - 1; + if (k < repair.numDeletions || (j - k) > (repair.distance - repair.numDeletions)) { + repair.code = SECONDARY_CODE; + repair.symbol = symbol; + repair.distance = j; + repair.stackPosition = top; + repair.bufferPosition = i; + repair.numDeletions = k; + repair.recoveryOnNextStack = stack_flag; + } + } + } + } + } + + return repair; + } + + +// +// This procedure is invoked to issue a secondary diagnosis and +// adjust the input buffer. The recovery in question is either +// an automatic scope recovery, a manual scope recovery, a +// secondary substitution or a secondary deletion. +// + private void secondaryDiagnosis(SecondaryRepairInfo repair) { + switch(repair.code) { + case SCOPE_CODE: { + if (repair.stackPosition < stateStackTop) { + reportError(DELETION_CODE, + Parser.terminal_index[ERROR_SYMBOL], + locationStack[repair.stackPosition], + buffer[1]); + } + for (int i = 0; i < scopeStackTop; i++) { + reportError(SCOPE_CODE, + -scopeIndex[i], + locationStack[scopePosition[i]], + buffer[1], + Parser.non_terminal_index[Parser.scope_lhs[scopeIndex[i]]]); + } + + repair.symbol = Parser.scope_lhs[scopeIndex[scopeStackTop]] + NT_OFFSET; + stateStackTop = scopePosition[scopeStackTop]; + reportError(SCOPE_CODE, + -scopeIndex[scopeStackTop], + locationStack[scopePosition[scopeStackTop]], + buffer[1], + getNtermIndex(stack[stateStackTop], + repair.symbol, + repair.bufferPosition) + ); + break; + } + default: { + reportError(repair.code, + (repair.code == SECONDARY_CODE + ? getNtermIndex(stack[repair.stackPosition], + repair.symbol, + repair.bufferPosition) + : Parser.terminal_index[ERROR_SYMBOL]), + locationStack[repair.stackPosition], + buffer[repair.bufferPosition - 1]); + stateStackTop = repair.stackPosition; + } + } + } + + + + +// +// Try to parse until first_token and all tokens in BUFFER have +// been consumed, or an error is encountered. Return the number +// of tokens that were expended before the parse blocked. +// + private int parseCheck(int stck[], int stack_top, int first_token, int buffer_position) { + int max_pos; + int indx; + int ct; + int act; + + // + // Initialize pointer for temp_stack and initialize maximum + // position of state stack that is still useful. + // + act = stck[stack_top]; + if (first_token > NT_OFFSET) { + tempStackTop = stack_top; + max_pos = stack_top; + indx = buffer_position; + ct = lexStream.kind(buffer[indx]); + lexStream.reset(lexStream.next(buffer[indx])); + int lhs_symbol = first_token - NT_OFFSET; + act = Parser.ntAction(act, lhs_symbol); + if (act <= NUM_RULES) { + do { + tempStackTop -= (Parser.rhs[act]-1); + lhs_symbol = Parser.lhs[act]; + act = (tempStackTop > max_pos + ? tempStack[tempStackTop] + : stck[tempStackTop]); + act = Parser.ntAction(act, lhs_symbol); + } while(act <= NUM_RULES); + + max_pos = max_pos < tempStackTop ? max_pos : tempStackTop; + } + } else { + tempStackTop = stack_top - 1; + max_pos = tempStackTop; + indx = buffer_position - 1; + ct = first_token; + lexStream.reset(buffer[buffer_position]); + } + + process_terminal: for (;;) { + if (++tempStackTop >= stackLength) // Stack overflow!!! + return indx; + tempStack[tempStackTop] = act; + + act = Parser.tAction(act, ct); + + if (act <= NUM_RULES) { // reduce action + tempStackTop--; + } else if (act < ACCEPT_ACTION || // shift action + act > ERROR_ACTION) { // shift-reduce action + if (indx == MAX_DISTANCE) + return indx; + indx++; + ct = lexStream.kind(buffer[indx]); + lexStream.reset(lexStream.next(buffer[indx])); + if (act > ERROR_ACTION) { + act -= ERROR_ACTION; + } else { + continue process_terminal; + } + } else if (act == ACCEPT_ACTION) { // accept action + return MAX_DISTANCE; + } else { + return indx; // error action + } + + process_non_terminal: + do { + tempStackTop -= (Parser.rhs[act]-1); + int lhs_symbol = Parser.lhs[act]; + act = (tempStackTop > max_pos + ? tempStack[tempStackTop] + : stck[tempStackTop]); + act = Parser.ntAction(act, lhs_symbol); + } while(act <= NUM_RULES); + + max_pos = max_pos < tempStackTop ? max_pos : tempStackTop; + } // process_terminal; + } + private void reportError(int msgCode, int nameIndex, int leftToken, int rightToken) { + reportError(msgCode, nameIndex, leftToken, rightToken, 0); + } + + private void reportError(int msgCode, int nameIndex, int leftToken, int rightToken, int scopeNameIndex) { + int lToken = (leftToken > rightToken ? rightToken : leftToken); + + if (lToken < rightToken) { + reportSecondaryError(msgCode, nameIndex, lToken, rightToken, scopeNameIndex); + } else { + reportPrimaryError(msgCode, nameIndex, rightToken, scopeNameIndex); + } + } + private void reportPrimaryError(int msgCode, int nameIndex, int token, int scopeNameIndex) { + String name; + if (nameIndex >= 0) { + name = Parser.readableName[nameIndex]; + } else { + name = EMPTY_STRING; + } + + int errorStart = lexStream.start(token); + int errorEnd = lexStream.end(token); + int currentKind = lexStream.kind(token); + String errorTokenName = Parser.name[Parser.terminal_index[lexStream.kind(token)]]; + char[] errorTokenSource = lexStream.name(token); + + switch(msgCode) { + case BEFORE_CODE: + problemReporter().parseErrorInsertBeforeToken( + errorStart, + errorEnd, + currentKind, + errorTokenSource, + errorTokenName, + name); + break; + case INSERTION_CODE: + problemReporter().parseErrorInsertAfterToken( + errorStart, + errorEnd, + currentKind, + errorTokenSource, + errorTokenName, + name); + break; + case DELETION_CODE: + problemReporter().parseErrorDeleteToken( + errorStart, + errorEnd, + currentKind, + errorTokenSource, + errorTokenName); + break; + case INVALID_CODE: + if (name.length() == 0) { + problemReporter().parseErrorReplaceToken( + errorStart, + errorEnd, + currentKind, + errorTokenSource, + errorTokenName, + name); + } else { + problemReporter().parseErrorInvalidToken( + errorStart, + errorEnd, + currentKind, + errorTokenSource, + errorTokenName, + name); + } + break; + case SUBSTITUTION_CODE: + problemReporter().parseErrorReplaceToken( + errorStart, + errorEnd, + currentKind, + errorTokenSource, + errorTokenName, + name); + break; + case SCOPE_CODE: + StringBuffer buf = new StringBuffer(); + for (int i = Parser.scope_suffix[- nameIndex]; Parser.scope_rhs[i] != 0; i++) { + buf.append(Parser.readableName[Parser.scope_rhs[i]]); + if (Parser.scope_rhs[i + 1] != 0) // any more symbols to print? + buf.append(' '); + + } + + if (scopeNameIndex != 0) { + problemReporter().parseErrorInsertToComplete( + errorStart, + errorEnd, + buf.toString(), + Parser.readableName[scopeNameIndex]); + } else { + problemReporter().parseErrorInsertToCompleteScope( + errorStart, + errorEnd, + buf.toString()); + } + + break; + case EOF_CODE: + problemReporter().parseErrorUnexpectedEnd( + errorStart, + errorEnd); + break; + case MERGE_CODE: + problemReporter().parseErrorMergeTokens( + errorStart, + errorEnd, + name); + break; + case MISPLACED_CODE: + problemReporter().parseErrorMisplacedConstruct( + errorStart, + errorEnd); + break; + default: + if (name.length() == 0) { + problemReporter().parseErrorNoSuggestion( + errorStart, + errorEnd, + currentKind, + errorTokenSource, + errorTokenName); + } else { + problemReporter().parseErrorReplaceToken( + errorStart, + errorEnd, + currentKind, + errorTokenSource, + errorTokenName, + name); + } + break; + } + } + + private void reportSecondaryError(int msgCode, int nameIndex, int leftToken, int rightToken, int scopeNameIndex) { + String name; + if (nameIndex >= 0) { + name = Parser.readableName[nameIndex]; + } else { + name = EMPTY_STRING; + } + + int errorStart = -1; + if(lexStream.isInsideStream(leftToken)) { + if(leftToken == 0) { + errorStart = lexStream.start(leftToken + 1); + } else { + errorStart = lexStream.start(leftToken); + } + } else { + if(leftToken == errorToken) { + errorStart = errorTokenStart; + } else { + for (int i = 0; i <= stateStackTop; i++) { + if(locationStack[i] == leftToken) { + errorStart = locationStartStack[i]; + } + } + } + if(errorStart == -1) { + errorStart = lexStream.start(rightToken); + } + } + int errorEnd = lexStream.end(rightToken); + + switch(msgCode) { + case MISPLACED_CODE: + problemReporter().parseErrorMisplacedConstruct( + errorStart, + errorEnd); + break; + case SCOPE_CODE: + // error start is on the last token start + errorStart = lexStream.start(rightToken); + + StringBuffer buf = new StringBuffer(); + for (int i = Parser.scope_suffix[- nameIndex]; Parser.scope_rhs[i] != 0; i++) { + buf.append(Parser.readableName[Parser.scope_rhs[i]]); + if (Parser.scope_rhs[i+1] != 0) + buf.append(' '); + } + if (scopeNameIndex != 0) { + problemReporter().parseErrorInsertToComplete( + errorStart, + errorEnd, + buf.toString(), + Parser.readableName[scopeNameIndex]); + } else { + problemReporter().parseErrorInsertToCompletePhrase( + errorStart, + errorEnd, + buf.toString()); + } + break; + case MERGE_CODE: + problemReporter().parseErrorMergeTokens( + errorStart, + errorEnd, + name); + break; + case DELETION_CODE: + problemReporter().parseErrorDeleteTokens( + errorStart, + errorEnd); + break; + default: + if (name.length() == 0) { + problemReporter().parseErrorNoSuggestionForTokens( + errorStart, + errorEnd); + } else { + problemReporter().parseErrorReplaceTokens( + errorStart, + errorEnd, + name); + } + } + return; + } + + public String toString() { + StringBuffer res = new StringBuffer(); + + res.append(lexStream.toString()); + + return res.toString(); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/diagnose/LexStream.java b/src/java/org/eclipse/jdt/internal/compiler/parser/diagnose/LexStream.java new file mode 100644 index 0000000..3231806 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/parser/diagnose/LexStream.java @@ -0,0 +1,270 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.parser.diagnose; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.core.compiler.InvalidInputException; +import org.eclipse.jdt.internal.compiler.parser.Scanner; +import org.eclipse.jdt.internal.compiler.parser.TerminalTokens; + +public class LexStream implements TerminalTokens { + public static final int IS_AFTER_JUMP = 1; + public static final int LBRACE_MISSING = 2; + + public class Token{ + int kind; + char[] name; + int start; + int end; + int line; + int flags; + + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append(name).append('[').append(kind).append(']'); + buffer.append('{').append(start).append(',').append(end).append('}').append(line); + return buffer.toString(); + } + + } + + private int tokenCacheIndex; + private int tokenCacheEOFIndex; + private Token[] tokenCache; + + private int currentIndex = -1; + + private Scanner scanner; + private int[] intervalStartToSkip; + private int[] intervalEndToSkip; + private int[] intervalFlagsToSkip; + + private int previousInterval = -1; + + public LexStream(int size, Scanner scanner, int[] intervalStartToSkip, int[] intervalEndToSkip, int[] intervalFlagsToSkip, int firstToken, int init, int eof) { + this.tokenCache = new Token[size]; + this.tokenCacheIndex = 0; + this.tokenCacheEOFIndex = Integer.MAX_VALUE; + this.tokenCache[0] = new Token(); + this.tokenCache[0].kind = firstToken; + this.tokenCache[0].name = CharOperation.NO_CHAR; + this.tokenCache[0].start = init; + this.tokenCache[0].end = init; + this.tokenCache[0].line = 0; + + this.intervalStartToSkip = intervalStartToSkip; + this.intervalEndToSkip = intervalEndToSkip; + this.intervalFlagsToSkip = intervalFlagsToSkip; + + scanner.resetTo(init, eof); + this.scanner = scanner; + } + + private void readTokenFromScanner(){ + int length = tokenCache.length; + boolean tokenNotFound = true; + + while(tokenNotFound) { + try { + int tokenKind = scanner.getNextToken(); + if(tokenKind != TokenNameEOF) { + int start = scanner.getCurrentTokenStartPosition(); + int end = scanner.getCurrentTokenEndPosition(); + if(!RangeUtil.isInInterval(start, end, intervalStartToSkip, intervalEndToSkip)) { + Token token = new Token(); + token.kind = tokenKind; + token.name = scanner.getCurrentTokenSource(); + token.start = start; + token.end = end; + token.line = scanner.getLineNumber(end); + + int pInterval = RangeUtil.getPreviousInterval(start, end, intervalStartToSkip, intervalEndToSkip); + if(pInterval != previousInterval && (intervalFlagsToSkip[previousInterval + 1] & RangeUtil.IGNORE) == 0){ + token.flags = IS_AFTER_JUMP; + if((intervalFlagsToSkip[pInterval] & RangeUtil.LBRACE_MISSING) != 0){ + token.flags |= LBRACE_MISSING; + } + } + previousInterval = pInterval; + + tokenCache[++tokenCacheIndex % length] = token; + + tokenNotFound = false; + } + } else { + int start = scanner.getCurrentTokenStartPosition(); + int end = scanner.getCurrentTokenEndPosition(); + Token token = new Token(); + token.kind = tokenKind; + token.name = CharOperation.NO_CHAR; + token.start = start; + token.end = end; + token.line = scanner.getLineNumber(end); + + tokenCache[++tokenCacheIndex % length] = token; + + tokenCacheEOFIndex = tokenCacheIndex; + tokenNotFound = false; + } + } catch (InvalidInputException e) { + // return next token + } + } + } + + public Token token(int index) { + if(index < 0) { + Token eofToken = new Token(); + eofToken.kind = TokenNameEOF; + eofToken.name = CharOperation.NO_CHAR; + return eofToken; + } + if(this.tokenCacheEOFIndex >= 0 && index > this.tokenCacheEOFIndex) { + return token(this.tokenCacheEOFIndex); + } + int length = tokenCache.length; + if(index > this.tokenCacheIndex) { + int tokensToRead = index - this.tokenCacheIndex; + while(tokensToRead-- != 0) { + readTokenFromScanner(); + } + } else if(this.tokenCacheIndex - length >= index) { + return null; + } + + return tokenCache[index % length]; + } + + + + public int getToken() { + return currentIndex = next(currentIndex); + } + + public int previous(int tokenIndex) { + return tokenIndex > 0 ? tokenIndex - 1 : 0; + } + + public int next(int tokenIndex) { + return tokenIndex < this.tokenCacheEOFIndex ? tokenIndex + 1 : this.tokenCacheEOFIndex; + } + + public boolean afterEol(int i) { + return i < 1 ? true : line(i - 1) < line(i); + } + + public void reset() { + currentIndex = -1; + } + + public void reset(int i) { + currentIndex = previous(i); + } + + public int badtoken() { + return 0; + } + + public int kind(int tokenIndex) { + return token(tokenIndex).kind; + } + + public char[] name(int tokenIndex) { + return token(tokenIndex).name; + } + + public int line(int tokenIndex) { + return token(tokenIndex).line; + } + + public int start(int tokenIndex) { + return token(tokenIndex).start; + } + + public int end(int tokenIndex) { + return token(tokenIndex).end; + } + + public int flags(int tokenIndex) { + return token(tokenIndex).flags; + } + + public boolean isInsideStream(int index) { + if(this.tokenCacheEOFIndex >= 0 && index > this.tokenCacheEOFIndex) { + return false; + } else if(index > this.tokenCacheIndex) { + return true; + } else if(this.tokenCacheIndex - tokenCache.length >= index) { + return false; + } else { + return true; + } + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + public String toString() { + StringBuffer res = new StringBuffer(); + + String source = new String(scanner.source); + if(currentIndex < 0) { + res.append(source); + } else { + Token token = token(currentIndex); + int curtokKind = token.kind; + int curtokStart = token.start; + int curtokEnd = token.end; + + int previousEnd = -1; + for (int i = 0; i < intervalStartToSkip.length; i++) { + int intervalStart = intervalStartToSkip[i]; + int intervalEnd = intervalEndToSkip[i]; + + if(curtokStart >= previousEnd && curtokEnd <= intervalStart) { + res.append(source.substring(previousEnd + 1, curtokStart)); + res.append('<'); + res.append('#'); + res.append(source.substring(curtokStart, curtokEnd + 1)); + res.append('#'); + res.append('>'); + res.append(source.substring(curtokEnd+1, intervalStart)); + } else { + res.append(source.substring(previousEnd + 1, intervalStart)); + } + res.append('<'); + res.append('@'); + res.append(source.substring(intervalStart, intervalEnd + 1)); + res.append('@'); + res.append('>'); + + previousEnd = intervalEnd; + } + if(curtokStart >= previousEnd) { + res.append(source.substring(previousEnd + 1, curtokStart)); + res.append('<'); + res.append('#'); + if(curtokKind == TokenNameEOF) { + res.append("EOF#>"); //$NON-NLS-1$ + } else { + res.append(source.substring(curtokStart, curtokEnd + 1)); + res.append('#'); + res.append('>'); + res.append(source.substring(curtokEnd+1)); + } + } else { + res.append(source.substring(previousEnd + 1)); + } + } + + return res.toString(); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/diagnose/RangeUtil.java b/src/java/org/eclipse/jdt/internal/compiler/parser/diagnose/RangeUtil.java new file mode 100644 index 0000000..4c53fa2 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/parser/diagnose/RangeUtil.java @@ -0,0 +1,200 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.parser.diagnose; + +import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; +import org.eclipse.jdt.internal.compiler.ast.Initializer; +import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; +import org.eclipse.jdt.internal.compiler.lookup.CompilerModifiers; + +public class RangeUtil { + + // flags + public static final int NO_FLAG = 0; + public static final int LBRACE_MISSING = 1; + public static final int IGNORE = 2; + + static class RangeResult { + private static final int INITIAL_SIZE = 10; + int pos; + int[] intervalStarts; + int[] intervalEnds; + int[] intervalFlags; + + RangeResult() { + this.pos = 0; + this.intervalStarts = new int[INITIAL_SIZE]; + this.intervalEnds = new int[INITIAL_SIZE]; + this.intervalFlags = new int[INITIAL_SIZE]; + } + + void addInterval(int start, int end){ + addInterval(start, end, NO_FLAG); + } + + void addInterval(int start, int end, int flags){ + if(pos >= intervalStarts.length) { + System.arraycopy(intervalStarts, 0, intervalStarts = new int[pos * 2], 0, pos); + System.arraycopy(intervalEnds, 0, intervalEnds = new int[pos * 2], 0, pos); + System.arraycopy(intervalFlags, 0, intervalFlags = new int[pos * 2], 0, pos); + } + intervalStarts[pos] = start; + intervalEnds[pos] = end; + intervalFlags[pos] = flags; + pos++; + } + + int[][] getRanges() { + int[] resultStarts = new int[pos]; + int[] resultEnds = new int[pos]; + int[] resultFlags = new int[pos]; + + System.arraycopy(intervalStarts, 0, resultStarts, 0, pos); + System.arraycopy(intervalEnds, 0, resultEnds, 0, pos); + System.arraycopy(intervalFlags, 0, resultFlags, 0, pos); + + if (resultStarts.length > 1) { + quickSort(resultStarts, resultEnds, resultFlags, 0, resultStarts.length - 1); + } + return new int[][]{resultStarts, resultEnds, resultFlags}; + } + + private void quickSort(int[] list, int[] list2, int[] list3, int left, int right) { + int original_left= left; + int original_right= right; + int mid= list[(left + right) / 2]; + do { + while (compare(list[left], mid) < 0) { + left++; + } + while (compare(mid, list[right]) < 0) { + right--; + } + if (left <= right) { + int tmp= list[left]; + list[left]= list[right]; + list[right]= tmp; + + tmp = list2[left]; + list2[left]= list2[right]; + list2[right]= tmp; + + tmp = list3[left]; + list3[left]= list3[right]; + list3[right]= tmp; + + left++; + right--; + } + } while (left <= right); + + if (original_left < right) { + quickSort(list, list2, list3, original_left, right); + } + if (left < original_right) { + quickSort(list, list2, list3, left, original_right); + } + } + + private int compare(int i1, int i2) { + return i1 - i2; + } + } + + + + public static boolean containsErrorInSignature(AbstractMethodDeclaration method){ + return method.sourceEnd + 1 == method.bodyStart || method.bodyEnd == method.declarationSourceEnd; + } + + public static int[][] computeDietRange(TypeDeclaration[] types) { + if(types == null || types.length == 0) { + return new int[3][0]; + } else { + RangeResult result = new RangeResult(); + computeDietRange0(types, result); + return result.getRanges(); + } + } + + private static void computeDietRange0(TypeDeclaration[] types, RangeResult result) { + for (int j = 0; j < types.length; j++) { + //members + TypeDeclaration[] memberTypeDeclarations = types[j].memberTypes; + if(memberTypeDeclarations != null && memberTypeDeclarations.length > 0) { + computeDietRange0(types[j].memberTypes, result); + } + //methods + AbstractMethodDeclaration[] methods = types[j].methods; + if (methods != null) { + int length = methods.length; + for (int i = 0; i < length; i++) { + AbstractMethodDeclaration method = methods[i]; + if(containsIgnoredBody(method)) { + if(containsErrorInSignature(method)) { + method.errorInSignature = true; + result.addInterval(method.declarationSourceStart, method.declarationSourceEnd, IGNORE); + } else { + int flags = method.sourceEnd + 1 == method.bodyStart ? LBRACE_MISSING : NO_FLAG; + result.addInterval(method.bodyStart, method.bodyEnd, flags); + } + } + } + } + + //initializers + FieldDeclaration[] fields = types[j].fields; + if (fields != null) { + int length = fields.length; + for (int i = 0; i < length; i++) { + if (fields[i] instanceof Initializer) { + Initializer initializer = (Initializer)fields[i]; + if(initializer.declarationSourceEnd == initializer.bodyEnd){ + initializer.errorInSignature = true; + result.addInterval(initializer.declarationSourceStart, initializer.declarationSourceEnd, IGNORE); + } else { + result.addInterval(initializer.bodyStart, initializer.bodyEnd); + } + } + } + } + } + } + + public static boolean isInInterval(int start, int end, int[] intervalStart, int[] intervalEnd) { + int length = intervalStart.length; + for (int i = 0; i < length; i++) { + if(intervalStart[i] <= start && intervalEnd[i] >= end) { + return true; + } else if(intervalStart[i] > end) { + return false; + } + } + return false; + } + + public static int getPreviousInterval(int start, int end, int[] intervalStart, int[] intervalEnd) { + int length = intervalStart.length; + for (int i = 0; i < length; i++) { + if(intervalStart[i] > end) { + return i - 1; + } + } + return length - 1; + } + + public static boolean containsIgnoredBody(AbstractMethodDeclaration method){ + return !method.isDefaultConstructor() + && !method.isClinit() + && (method.modifiers & CompilerModifiers.AccSemicolonBody) == 0; + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/parser1.rsc b/src/java/org/eclipse/jdt/internal/compiler/parser/parser1.rsc new file mode 100644 index 0000000..a35d6d8 Binary files /dev/null and b/src/java/org/eclipse/jdt/internal/compiler/parser/parser1.rsc differ diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/parser10.rsc b/src/java/org/eclipse/jdt/internal/compiler/parser/parser10.rsc new file mode 100644 index 0000000..57084e8 Binary files /dev/null and b/src/java/org/eclipse/jdt/internal/compiler/parser/parser10.rsc differ diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/parser11.rsc b/src/java/org/eclipse/jdt/internal/compiler/parser/parser11.rsc new file mode 100644 index 0000000..4ed7d3b Binary files /dev/null and b/src/java/org/eclipse/jdt/internal/compiler/parser/parser11.rsc differ diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/parser12.rsc b/src/java/org/eclipse/jdt/internal/compiler/parser/parser12.rsc new file mode 100644 index 0000000..a114c91 Binary files /dev/null and b/src/java/org/eclipse/jdt/internal/compiler/parser/parser12.rsc differ diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/parser13.rsc b/src/java/org/eclipse/jdt/internal/compiler/parser/parser13.rsc new file mode 100644 index 0000000..6b56156 Binary files /dev/null and b/src/java/org/eclipse/jdt/internal/compiler/parser/parser13.rsc differ diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/parser14.rsc b/src/java/org/eclipse/jdt/internal/compiler/parser/parser14.rsc new file mode 100644 index 0000000..e701a9e Binary files /dev/null and b/src/java/org/eclipse/jdt/internal/compiler/parser/parser14.rsc differ diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/parser15.rsc b/src/java/org/eclipse/jdt/internal/compiler/parser/parser15.rsc new file mode 100644 index 0000000..4497913 Binary files /dev/null and b/src/java/org/eclipse/jdt/internal/compiler/parser/parser15.rsc differ diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/parser16.rsc b/src/java/org/eclipse/jdt/internal/compiler/parser/parser16.rsc new file mode 100644 index 0000000..0046bb9 Binary files /dev/null and b/src/java/org/eclipse/jdt/internal/compiler/parser/parser16.rsc differ diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/parser17.rsc b/src/java/org/eclipse/jdt/internal/compiler/parser/parser17.rsc new file mode 100644 index 0000000..ca3af17 Binary files /dev/null and b/src/java/org/eclipse/jdt/internal/compiler/parser/parser17.rsc differ diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/parser18.rsc b/src/java/org/eclipse/jdt/internal/compiler/parser/parser18.rsc new file mode 100644 index 0000000..66f0156 Binary files /dev/null and b/src/java/org/eclipse/jdt/internal/compiler/parser/parser18.rsc differ diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/parser19.rsc b/src/java/org/eclipse/jdt/internal/compiler/parser/parser19.rsc new file mode 100644 index 0000000..0f1c471 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/parser/parser19.rsc @@ -0,0 +1 @@ +WWEEE;;X(((5EV5(((((S5F ZZ \ No newline at end of file diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/parser2.rsc b/src/java/org/eclipse/jdt/internal/compiler/parser/parser2.rsc new file mode 100644 index 0000000..3d7327b Binary files /dev/null and b/src/java/org/eclipse/jdt/internal/compiler/parser/parser2.rsc differ diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/parser20.rsc b/src/java/org/eclipse/jdt/internal/compiler/parser/parser20.rsc new file mode 100644 index 0000000..8dc5ace Binary files /dev/null and b/src/java/org/eclipse/jdt/internal/compiler/parser/parser20.rsc differ diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/parser3.rsc b/src/java/org/eclipse/jdt/internal/compiler/parser/parser3.rsc new file mode 100644 index 0000000..81f96e1 Binary files /dev/null and b/src/java/org/eclipse/jdt/internal/compiler/parser/parser3.rsc differ diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/parser4.rsc b/src/java/org/eclipse/jdt/internal/compiler/parser/parser4.rsc new file mode 100644 index 0000000..2842e17 Binary files /dev/null and b/src/java/org/eclipse/jdt/internal/compiler/parser/parser4.rsc differ diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/parser5.rsc b/src/java/org/eclipse/jdt/internal/compiler/parser/parser5.rsc new file mode 100644 index 0000000..26aa971 Binary files /dev/null and b/src/java/org/eclipse/jdt/internal/compiler/parser/parser5.rsc differ diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/parser6.rsc b/src/java/org/eclipse/jdt/internal/compiler/parser/parser6.rsc new file mode 100644 index 0000000..69c1580 Binary files /dev/null and b/src/java/org/eclipse/jdt/internal/compiler/parser/parser6.rsc differ diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/parser7.rsc b/src/java/org/eclipse/jdt/internal/compiler/parser/parser7.rsc new file mode 100644 index 0000000..a4e445a Binary files /dev/null and b/src/java/org/eclipse/jdt/internal/compiler/parser/parser7.rsc differ diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/parser8.rsc b/src/java/org/eclipse/jdt/internal/compiler/parser/parser8.rsc new file mode 100644 index 0000000..8ce79a7 Binary files /dev/null and b/src/java/org/eclipse/jdt/internal/compiler/parser/parser8.rsc differ diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/parser9.rsc b/src/java/org/eclipse/jdt/internal/compiler/parser/parser9.rsc new file mode 100644 index 0000000..6f68468 Binary files /dev/null and b/src/java/org/eclipse/jdt/internal/compiler/parser/parser9.rsc differ diff --git a/src/java/org/eclipse/jdt/internal/compiler/parser/readableNames.properties b/src/java/org/eclipse/jdt/internal/compiler/parser/readableNames.properties new file mode 100644 index 0000000..ecc98bf --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/parser/readableNames.properties @@ -0,0 +1,202 @@ +,opt=, +AbstractMethodDeclaration=AbstractMethodDeclaration +AdditiveExpression=Expression +AllocationHeader=AllocationHeader +AndExpression=Expression +ArgumentList=ArgumentList +ArgumentListopt=ArgumentList +ArrayAccess=ArrayAccess +ArrayCreationHeader=ArrayCreationHeader +ArrayCreationWithArrayInitializer=ArrayCreationWithArrayInitializer +ArrayCreationWithoutArrayInitializer=ArrayCreationWithoutArrayInitializer +ArrayInitializer=ArrayInitializer +ArrayType=ArrayType +AssertStatement=AssertStatement +Assignment=Assignment +AssignmentExpression=Expression +AssignmentOperator=AssignmentOperator +Block=Block +BlockStatement=BlockStatement +BlockStatements=BlockStatements +BlockStatementsopt=BlockStatements +BooleanLiteral=BooleanLiteral +BreakStatement=BreakStatement +CastExpression=CastExpression +CatchClause=CatchClause +CatchHeader=CatchHeader +Catches=Catches +Catchesopt=Catches +ClassBody=ClassBody +ClassBodyDeclaration=ClassBodyDeclaration +ClassBodyDeclarations=ClassBodyDeclarations +ClassBodyDeclarationsopt=ClassBodyDeclarations +ClassBodyopt=ClassBody +ClassDeclaration=ClassDeclaration +ClassHeader=ClassHeader +ClassHeaderExtends=ClassHeaderExtends +ClassHeaderExtendsopt=ClassHeaderExtends +ClassHeaderImplements=ClassHeaderImplements +ClassHeaderImplementsopt=ClassHeaderImplements +ClassHeaderName=ClassHeaderName +ClassInstanceCreationExpression=ClassInstanceCreationExpression +ClassInstanceCreationExpressionName=ClassInstanceCreationExpressionName +ClassMemberDeclaration=ClassMemberDeclaration +ClassOrInterfaceType=Type +ClassType=ClassType +ClassTypeElt=ClassType +ClassTypeList=ClassTypeList +CompilationUnit=CompilationUnit +ConditionalAndExpression=Expression +ConditionalExpression=Expression +ConditionalOrExpression=Expression +ConstantDeclaration=ConstantDeclaration +ConstantExpression=ConstantExpression +ConstructorDeclaration=ConstructorDeclaration +ConstructorHeader=ConstructorHeader +ConstructorHeaderName=ConstructorHeaderName +ContinueStatement=ContinueStatement +Diet=Diet +DimWithOrWithOutExpr=Dimension +DimWithOrWithOutExprs=Dimensions +Dims=Dimensions +DimsLoop=Dimensions +Dimsopt=Dimensions +DoStatement=DoStatement +EmptyStatement=EmptyStatement +EnterAnonymousClassBody=EnterAnonymousClassBody +EnterCompilationUnit=EnterCompilationUnit +EnterVariable=EnterVariable +EqualityExpression=Expression +ExclusiveOrExpression=Expression +ExitTryBlock=ExitTryBlock +ExitVariableWithInitialization=ExitVariableWithInitialization +ExitVariableWithoutInitialization=ExitVariableWithoutInitialization +ExplicitConstructorInvocation=ExplicitConstructorInvocation +Expression=Expression +ExpressionStatement=Statement +Expressionopt=Expression +FieldAccess=FieldAccess +FieldDeclaration=FieldDeclaration +Finally=Finally +FloatingPointType=FloatingPointType +ForInit=ForInit +ForInitopt=ForInit +ForStatement=ForStatement +ForStatementNoShortIf=ForStatement +ForUpdate=ForUpdate +ForUpdateopt=ForUpdate +ForceNoDiet=ForceNoDiet +FormalParameter=FormalParameter +FormalParameterList=FormalParameterList +FormalParameterListopt=FormalParameterList +GenericMethodDeclaration=GenericMethodDeclaration +Goal=Goal +Header=Header +Headers=Headers +IfThenElseStatement=IfStatement +IfThenElseStatementNoShortIf=IfStatement +IfThenStatement=IfStatement +ImportDeclaration=ImportDeclaration +ImportDeclarations=ImportDeclarations +ImportDeclarationsopt=ImportDeclarations +InclusiveOrExpression=Expression +Initializer=Initializer +InsideCastExpression=InsideCastExpression +InsideCastExpressionLL1=InsideCastExpression +IntegralType=IntegralType +InterfaceBody=InterfaceBody +InterfaceDeclaration=InterfaceDeclaration +InterfaceHeader=InterfaceHeader +InterfaceHeaderExtends=InterfaceHeaderExtends +InterfaceHeaderExtendsopt=InterfaceHeaderExtends +InterfaceHeaderName=InterfaceHeaderName +InterfaceMemberDeclaration=InterfaceMemberDeclaration +InterfaceMemberDeclarations=InterfaceMemberDeclarations +InterfaceMemberDeclarationsopt=InterfaceMemberDeclarations +InterfaceType=InterfaceType +InterfaceTypeList=InterfaceTypeList +InvalidArrayInitializerAssignement=ArrayInitializerAssignement +InvalidConstructorDeclaration=InvalidConstructorDeclaration +InvalidInterfaceDeclaration=InvalidInterfaceDeclaration +InvalidMethodDeclaration=InvalidMethodDeclaration +LabeledStatement=LabeledStatement +LabeledStatementNoShortIf=LabeledStatement +Literal=Literal +LocalVariableDeclaration=LocalVariableDeclaration +LocalVariableDeclarationStatement=LocalVariableDeclarationStatement +MethodBody=MethodBody +MethodDeclaration=MethodDeclaration +MethodHeader=MethodHeader +MethodHeaderExtendedDims=MethodHeaderExtendedDims +MethodHeaderName=MethodHeaderName +MethodHeaderParameters=MethodHeaderParameters +MethodHeaderThrowsClause=MethodHeaderThrowsClause +MethodHeaderThrowsClauseopt=MethodHeaderThrowsClause +MethodInvocation=MethodInvocation +Modifier=Modifier +Modifiers=Modifiers +Modifiersopt=Modifiers +MultiplicativeExpression=Expression +Name=Name +NestedMethod=NestedMethod +NestedType=NestedType +NumericType=NumericType +OneDimLoop=Dimension +OnlySynchronized=OnlySynchronized +OpenBlock=OpenBlock +PackageDeclaration=PackageDeclaration +PackageDeclarationName=PackageDeclarationName +PackageDeclarationopt=PackageDeclaration +PostDecrementExpression=PostDecrementExpression +PostIncrementExpression=PostIncrementExpression +PostfixExpression=Expression +PreDecrementExpression=PreDecrementExpression +PreIncrementExpression=PreIncrementExpression +Primary=Expression +PrimaryNoNewArray=Expression +PrimitiveType=PrimitiveType +PushLPAREN=( +PushModifiers=PushModifiers +PushPosition=PushPosition +PushRPAREN=) +QualifiedName=QualifiedName +ReferenceType=ReferenceType +RelationalExpression=Expression +RestoreDiet=RestoreDiet +ReturnStatement=ReturnStatement +ShiftExpression=Expression +SimpleName=SimpleName +SingleTypeImportDeclaration=SingleTypeImportDeclaration +SingleTypeImportDeclarationName=SingleTypeImportDeclarationName +Statement=Statement +StatementExpression=Expression +StatementExpressionList=StatementExpressionList +StatementNoShortIf=Statement +StatementWithoutTrailingSubstatement=Statement +StaticInitializer=StaticInitializer +StaticOnly=StaticOnly +SwitchBlock=SwitchBlock +SwitchBlockStatement=SwitchBlockStatement +SwitchBlockStatements=SwitchBlockStatements +SwitchLabel=SwitchLabel +SwitchLabels=SwitchLabels +SwitchStatement=SwitchStatement +SynchronizedStatement=SynchronizedStatement +ThrowStatement=ThrowStatement +TryBlock=Block +TryStatement=TryStatement +Type=Type +TypeDeclaration=TypeDeclaration +TypeDeclarations=TypeDeclarations +TypeDeclarationsopt=TypeDeclarations +TypeImportOnDemandDeclaration=TypeImportOnDemandDeclaration +TypeImportOnDemandDeclarationName=TypeImportOnDemandDeclarationName +UnaryExpression=Expression +UnaryExpressionNotPlusMinus=Expression +VariableDeclarator=VariableDeclarator +VariableDeclaratorId=VariableDeclaratorId +VariableDeclarators=VariableDeclarators +VariableInitializer=VariableInitializer +VariableInitializers=VariableInitializers +WhileStatement=WhileStatement +WhileStatementNoShortIf=WhileStatement diff --git a/src/java/org/eclipse/jdt/internal/compiler/problem/AbortCompilation.java b/src/java/org/eclipse/jdt/internal/compiler/problem/AbortCompilation.java new file mode 100644 index 0000000..88e143d --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/problem/AbortCompilation.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.problem; + +import org.eclipse.jdt.core.compiler.IProblem; +import org.eclipse.jdt.internal.compiler.CompilationResult; +import org.eclipse.jdt.internal.compiler.ast.ASTNode; +import org.eclipse.jdt.internal.compiler.lookup.InvocationSite; + +/* + * Special unchecked exception type used + * to abort from the compilation process + * + * should only be thrown from within problem handlers. + */ +public class AbortCompilation extends RuntimeException { + + public CompilationResult compilationResult; + public Throwable exception; + public IProblem problem; + + /* special fields used to abort silently (e.g. when cancelling build process) */ + public boolean isSilent; + public RuntimeException silentException; + + private static final long serialVersionUID = -2047226595083244852L; // backward compatible + + public AbortCompilation() { + // empty + } + + public AbortCompilation(CompilationResult compilationResult, IProblem problem) { + this(); + this.compilationResult = compilationResult; + this.problem = problem; + } + + public AbortCompilation(CompilationResult compilationResult, Throwable exception) { + this(); + this.compilationResult = compilationResult; + this.exception = exception; + } + + public AbortCompilation(boolean isSilent, RuntimeException silentException) { + this(); + this.isSilent = isSilent; + this.silentException = silentException; + } + + public void updateContext(InvocationSite invocationSite, CompilationResult unitResult) { + if (this.problem == null) return; + if (this.problem.getSourceStart() != 0 || this.problem.getSourceEnd() != 0) return; + this.problem.setSourceStart(invocationSite.sourceStart()); + this.problem.setSourceEnd(invocationSite.sourceEnd()); + this.problem.setSourceLineNumber(ProblemHandler.searchLineNumber(unitResult.lineSeparatorPositions, invocationSite.sourceStart())); + this.compilationResult = unitResult; + } + + public void updateContext(ASTNode astNode, CompilationResult unitResult) { + if (this.problem == null) return; + if (this.problem.getSourceStart() != 0 || this.problem.getSourceEnd() != 0) return; + this.problem.setSourceStart(astNode.sourceStart()); + this.problem.setSourceEnd(astNode.sourceEnd()); + this.problem.setSourceLineNumber(ProblemHandler.searchLineNumber(unitResult.lineSeparatorPositions, astNode.sourceStart())); + this.compilationResult = unitResult; + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/problem/AbortCompilationUnit.java b/src/java/org/eclipse/jdt/internal/compiler/problem/AbortCompilationUnit.java new file mode 100644 index 0000000..d75e6ae --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/problem/AbortCompilationUnit.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.problem; + +import org.eclipse.jdt.core.compiler.IProblem; +import org.eclipse.jdt.internal.compiler.CompilationResult; + +/* + * Special unchecked exception type used + * to abort from the compilation process + * + * should only be thrown from within problem handlers. + */ +public class AbortCompilationUnit extends AbortCompilation { + + private static final long serialVersionUID = -4253893529982226734L; // backward compatible + +public AbortCompilationUnit(CompilationResult compilationResult, IProblem problem) { + super(compilationResult, problem); +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/problem/AbortMethod.java b/src/java/org/eclipse/jdt/internal/compiler/problem/AbortMethod.java new file mode 100644 index 0000000..7feb32e --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/problem/AbortMethod.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.problem; + +import org.eclipse.jdt.core.compiler.IProblem; +import org.eclipse.jdt.internal.compiler.CompilationResult; + +/* + * Special unchecked exception type used + * to abort from the compilation process + * + * should only be thrown from within problem handlers. + */ +public class AbortMethod extends AbortType { + + private static final long serialVersionUID = -1480267398969840003L; // backward compatible + +public AbortMethod(CompilationResult compilationResult, IProblem problem) { + super(compilationResult, problem); +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/problem/AbortType.java b/src/java/org/eclipse/jdt/internal/compiler/problem/AbortType.java new file mode 100644 index 0000000..f357469 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/problem/AbortType.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.problem; + +import org.eclipse.jdt.core.compiler.IProblem; +import org.eclipse.jdt.internal.compiler.CompilationResult; + +/* + * Special unchecked exception type used + * to abort from the compilation process + * + * should only be thrown from within problem handlers. + */ +public class AbortType extends AbortCompilationUnit { + + private static final long serialVersionUID = -5882417089349134385L; // backward compatible + +public AbortType(CompilationResult compilationResult, IProblem problem) { + super(compilationResult, problem); +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/problem/DefaultProblem.java b/src/java/org/eclipse/jdt/internal/compiler/problem/DefaultProblem.java new file mode 100644 index 0000000..8ec8619 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/problem/DefaultProblem.java @@ -0,0 +1,227 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.problem; + +import org.eclipse.jdt.core.compiler.IProblem; +import org.eclipse.jdt.internal.compiler.util.Util; + +public class DefaultProblem implements ProblemSeverities, IProblem { + + private static final String LINE_DELIMITER = System.getProperty("line.separator"); //$NON-NLS-1$ + + private char[] fileName; + private int id; + private int startPosition, endPosition, line; + private int severity; + private String[] arguments; + private String message; + + public DefaultProblem( + char[] originatingFileName, + String message, + int id, + String[] stringArguments, + int severity, + int startPosition, + int endPosition, + int line) { + + this.fileName = originatingFileName; + this.message = message; + this.id = id; + this.arguments = stringArguments; + this.severity = severity; + this.startPosition = startPosition; + this.endPosition = endPosition; + this.line = line; + } + public String errorReportSource(char[] unitSource) { + //extra from the source the innacurate token + //and "highlight" it using some underneath ^^^^^ + //put some context around too. + + //this code assumes that the font used in the console is fixed size + + //sanity ..... + if ((this.startPosition > this.endPosition) + || ((this.startPosition < 0) && (this.endPosition < 0))) + return Util.bind("problem.noSourceInformation"); //$NON-NLS-1$ + + StringBuffer errorBuffer = new StringBuffer(" "); //$NON-NLS-1$ + errorBuffer.append(Util.bind("problem.atLine", String.valueOf(this.line))); //$NON-NLS-1$ + errorBuffer.append(LINE_DELIMITER).append("\t"); //$NON-NLS-1$ + + char c; + final char SPACE = '\u0020'; + final char MARK = '^'; + final char TAB = '\t'; + //the next code tries to underline the token..... + //it assumes (for a good display) that token source does not + //contain any \r \n. This is false on statements ! + //(the code still works but the display is not optimal !) + + // expand to line limits + int length = unitSource.length, begin, end; + for (begin = this.startPosition >= length ? length - 1 : this.startPosition; begin > 0; begin--) { + if ((c = unitSource[begin - 1]) == '\n' || c == '\r') break; + } + for (end = this.endPosition >= length ? length - 1 : this.endPosition ; end+1 < length; end++) { + if ((c = unitSource[end + 1]) == '\r' || c == '\n') break; + } + + // trim left and right spaces/tabs + while ((c = unitSource[begin]) == ' ' || c == '\t') begin++; + //while ((c = unitSource[end]) == ' ' || c == '\t') end--; TODO (philippe) should also trim right, but all tests are to be updated + + // copy source + errorBuffer.append(unitSource, begin, end-begin+1); + errorBuffer.append(LINE_DELIMITER).append("\t"); //$NON-NLS-1$ + + // compute underline + for (int i = begin; i = length ? length - 1 : this.endPosition); i++) { + errorBuffer.append(MARK); + } + return errorBuffer.toString(); + } + + /** + * Answer back the original arguments recorded into the problem. + * @return java.lang.String[] + */ + public String[] getArguments() { + + return this.arguments; + } + + /** + * Answer the type of problem. + * @see org.eclipse.jdt.core.compiler.IProblem#getID() + * @return int + */ + public int getID() { + + return this.id; + } + + /** + * Answer a localized, human-readable message string which describes the problem. + * @return java.lang.String + */ + public String getMessage() { + + return this.message; + } + + /** + * Answer the file name in which the problem was found. + * @return char[] + */ + public char[] getOriginatingFileName() { + + return this.fileName; + } + + /** + * Answer the end position of the problem (inclusive), or -1 if unknown. + * @return int + */ + public int getSourceEnd() { + + return this.endPosition; + } + + /** + * Answer the line number in source where the problem begins. + * @return int + */ + public int getSourceLineNumber() { + + return this.line; + } + + /** + * Answer the start position of the problem (inclusive), or -1 if unknown. + * @return int + */ + public int getSourceStart() { + + return this.startPosition; + } + + /* + * Helper method: checks the severity to see if the Error bit is set. + * @return boolean + */ + public boolean isError() { + + return (this.severity & ProblemSeverities.Error) != 0; + } + + /* + * Helper method: checks the severity to see if the Error bit is not set. + * @return boolean + */ + public boolean isWarning() { + + return (this.severity & ProblemSeverities.Error) == 0; + } + + public void setOriginatingFileName(char[] fileName) { + this.fileName = fileName; + } + + /** + * Set the end position of the problem (inclusive), or -1 if unknown. + * + * Used for shifting problem positions. + * @param sourceEnd the new value of the sourceEnd of the receiver + */ + public void setSourceEnd(int sourceEnd) { + + this.endPosition = sourceEnd; + } + + /** + * Set the line number in source where the problem begins. + * @param lineNumber the new value of the line number of the receiver + */ + public void setSourceLineNumber(int lineNumber) { + + this.line = lineNumber; + } + + /** + * Set the start position of the problem (inclusive), or -1 if unknown. + * + * Used for shifting problem positions. + * @param sourceStart the new value of the source start position of the receiver + */ + public void setSourceStart(int sourceStart) { + + this.startPosition = sourceStart; + } + + public String toString() { + + String s = "Pb(" + (this.id & IgnoreCategoriesMask) + ") "; //$NON-NLS-1$ //$NON-NLS-2$ + if (this.message != null) { + s += this.message; + } else { + if (this.arguments != null) + for (int i = 0; i < this.arguments.length; i++) + s += " " + this.arguments[i]; //$NON-NLS-1$ + } + return s; + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/problem/DefaultProblemFactory.java b/src/java/org/eclipse/jdt/internal/compiler/problem/DefaultProblemFactory.java new file mode 100644 index 0000000..065c525 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/problem/DefaultProblemFactory.java @@ -0,0 +1,197 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.problem; + +import java.util.Enumeration; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +import org.eclipse.jdt.core.compiler.*; +import org.eclipse.jdt.core.compiler.IProblem; +import org.eclipse.jdt.internal.compiler.IProblemFactory; +import org.eclipse.jdt.internal.compiler.util.HashtableOfInt; +import org.eclipse.jdt.internal.compiler.util.Util; + +public class DefaultProblemFactory implements IProblemFactory { + + public HashtableOfInt messageTemplates; + private Locale locale; + private static HashtableOfInt DEFAULT_LOCALE_TEMPLATES; + private final static char[] DOUBLE_QUOTES = "''".toCharArray(); //$NON-NLS-1$ + private final static char[] SINGLE_QUOTE = "'".toCharArray(); //$NON-NLS-1$ + +public DefaultProblemFactory() { + this(Locale.getDefault()); +} +/** + * @param loc the locale used to get the right message + */ +public DefaultProblemFactory(Locale loc) { + this.locale = loc; + if (Locale.getDefault().equals(loc)){ + if (DEFAULT_LOCALE_TEMPLATES == null){ + DEFAULT_LOCALE_TEMPLATES = loadMessageTemplates(loc); + } + this.messageTemplates = DEFAULT_LOCALE_TEMPLATES; + } else { + this.messageTemplates = loadMessageTemplates(loc); + } +} +/** + * Answer a new IProblem created according to the parameters value + *
    + *
  • originatingFileName the name of the file name from which the problem is originated + *
  • problemId the problem id + *
  • problemArguments the fully qualified arguments recorded inside the problem + *
  • messageArguments the arguments needed to set the error message (shorter names than problemArguments ones) + *
  • severity the severity of the problem + *
  • startPosition the starting position of the problem + *
  • endPosition the end position of the problem + *
  • lineNumber the line on which the problem occured + *
+ * @param originatingFileName char[] + * @param problemId int + * @param problemArguments String[] + * @param messageArguments String[] + * @param severity int + * @param startPosition int + * @param endPosition int + * @param lineNumber int + * @return org.eclipse.jdt.internal.compiler.IProblem + */ +public IProblem createProblem( + char[] originatingFileName, + int problemId, + String[] problemArguments, + String[] messageArguments, + int severity, + int startPosition, + int endPosition, + int lineNumber) { + + return new DefaultProblem( + originatingFileName, + this.getLocalizedMessage(problemId, messageArguments), + problemId, + problemArguments, + severity, + startPosition, + endPosition, + lineNumber); +} +private final static int keyFromID(int id) { + return id + 1; // keys are offsetted by one in table, since it cannot handle 0 key +} +/** + * Answer the locale used to retrieve the error messages + * @return java.util.Locale + */ +public Locale getLocale() { + return this.locale; +} +public final String getLocalizedMessage(int id, String[] problemArguments) { + String message = (String) this.messageTemplates.get(keyFromID(id & IProblem.IgnoreCategoriesMask)); + if (message == null) { + return "Unable to retrieve the error message for problem id: " //$NON-NLS-1$ + + (id & IProblem.IgnoreCategoriesMask) + + ". Check compiler resources."; //$NON-NLS-1$ + } + + // for compatibility with MessageFormat which eliminates double quotes in original message + char[] messageWithNoDoubleQuotes = + CharOperation.replace(message.toCharArray(), DOUBLE_QUOTES, SINGLE_QUOTE); + + if (problemArguments == null) return new String(messageWithNoDoubleQuotes); + + int length = messageWithNoDoubleQuotes.length; + int start = 0; + int end = length; + StringBuffer output = null; + if ((id & IProblem.Javadoc) != 0) { + if (output == null) output = new StringBuffer(10+length+problemArguments.length*20); + output.append((String) this.messageTemplates.get(keyFromID(IProblem.JavadocMessagePrefix & IProblem.IgnoreCategoriesMask))); + } + while (true) { + if ((end = CharOperation.indexOf('{', messageWithNoDoubleQuotes, start)) > -1) { + if (output == null) output = new StringBuffer(length+problemArguments.length*20); + output.append(messageWithNoDoubleQuotes, start, end - start); + if ((start = CharOperation.indexOf('}', messageWithNoDoubleQuotes, end + 1)) > -1) { + int index = -1; + String argId = new String(messageWithNoDoubleQuotes, end + 1, start - end - 1); + try { + index = Integer.parseInt(argId); + output.append(problemArguments[index]); + } catch (NumberFormatException nfe) { + output.append(messageWithNoDoubleQuotes, end + 1, start - end); + } catch (ArrayIndexOutOfBoundsException e) { + return "Cannot bind message for problem (id: " //$NON-NLS-1$ + + (id & IProblem.IgnoreCategoriesMask) + + ") \"" //$NON-NLS-1$ + + message + + "\" with arguments: {" //$NON-NLS-1$ + + Util.toString(problemArguments) + +"}"; //$NON-NLS-1$ + } + start++; + } else { + output.append(messageWithNoDoubleQuotes, end, length); + break; + } + } else { + if (output == null) return new String(messageWithNoDoubleQuotes); + output.append(messageWithNoDoubleQuotes, start, length - start); + break; + } + } + + return output.toString(); +} +/** + * @param problem org.eclipse.jdt.internal.compiler.IProblem + * @return String + */ +public final String localizedMessage(IProblem problem) { + return getLocalizedMessage(problem.getID(), problem.getArguments()); +} + +/** + * This method initializes the MessageTemplates class variable according + * to the current Locale. + * @param loc Locale + * @return HashtableOfInt + */ +public static HashtableOfInt loadMessageTemplates(Locale loc) { + ResourceBundle bundle = null; + String bundleName = "org.eclipse.jdt.internal.compiler.problem.messages"; //$NON-NLS-1$ + try { + bundle = ResourceBundle.getBundle(bundleName, loc); + } catch(MissingResourceException e) { + System.out.println("Missing resource : " + bundleName.replace('.', '/') + ".properties for locale " + loc); //$NON-NLS-1$//$NON-NLS-2$ + throw e; + } + HashtableOfInt templates = new HashtableOfInt(700); + Enumeration keys = bundle.getKeys(); + while (keys.hasMoreElements()) { + String key = (String)keys.nextElement(); + try { + int messageID = Integer.parseInt(key); + templates.put(keyFromID(messageID), bundle.getString(key)); + } catch(NumberFormatException e) { + // key ill-formed + } catch (MissingResourceException e) { + // available ID + } + } + return templates; +} + +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/problem/ProblemHandler.java b/src/java/org/eclipse/jdt/internal/compiler/problem/ProblemHandler.java new file mode 100644 index 0000000..5b334d2 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/problem/ProblemHandler.java @@ -0,0 +1,183 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.problem; + +import org.eclipse.jdt.core.compiler.IProblem; +import org.eclipse.jdt.internal.compiler.CompilationResult; +import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy; +import org.eclipse.jdt.internal.compiler.IProblemFactory; +import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; +import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; + +/* + * Compiler error handler, responsible to determine whether + * a problem is actually a warning or an error; also will + * decide whether the compilation task can be processed further or not. + * + * Behavior : will request its current policy if need to stop on + * first error, and if should proceed (persist) with problems. + */ + +public class ProblemHandler implements ProblemSeverities { + + public final static String[] NoArgument = new String[0]; + + final public IErrorHandlingPolicy policy; + public final IProblemFactory problemFactory; + public final CompilerOptions options; +/* + * Problem handler can be supplied with a policy to specify + * its behavior in error handling. Also see static methods for + * built-in policies. + * + */ +public ProblemHandler(IErrorHandlingPolicy policy, CompilerOptions options, IProblemFactory problemFactory) { + this.policy = policy; + this.problemFactory = problemFactory; + this.options = options; +} +/* + * Given the current configuration, answers which category the problem + * falls into: + * Error | Warning | Ignore + */ +public int computeSeverity(int problemId){ + + return Error; // by default all problems are errors +} +public IProblem createProblem( + char[] fileName, + int problemId, + String[] problemArguments, + String[] messageArguments, + int severity, + int problemStartPosition, + int problemEndPosition, + int lineNumber) { + + return this.problemFactory.createProblem( + fileName, + problemId, + problemArguments, + messageArguments, + severity, + problemStartPosition, + problemEndPosition, + lineNumber); +} +public void handle( + int problemId, + String[] problemArguments, + String[] messageArguments, + int severity, + int problemStartPosition, + int problemEndPosition, + ReferenceContext referenceContext, + CompilationResult unitResult) { + + if (severity == Ignore) + return; + + // if no reference context, we need to abort from the current compilation process + if (referenceContext == null) { + if ((severity & Error) != 0) { // non reportable error is fatal + IProblem problem = this.createProblem(null, problemId, problemArguments, messageArguments, severity, 0, 0, 0); + throw new AbortCompilation(null, problem); + } else { + return; // ignore non reportable warning + } + } + + IProblem problem = + this.createProblem( + unitResult.getFileName(), + problemId, + problemArguments, + messageArguments, + severity, + problemStartPosition, + problemEndPosition, + problemStartPosition >= 0 + ? searchLineNumber(unitResult.lineSeparatorPositions, problemStartPosition) + : 0); + if (problem == null) return; // problem couldn't be created, ignore + + switch (severity & Error) { + case Error : + this.record(problem, unitResult, referenceContext); + referenceContext.tagAsHavingErrors(); + + // should abort ? + int abortLevel; + if ((abortLevel = + (this.policy.stopOnFirstError() ? AbortCompilation : severity & Abort)) != 0) { + + referenceContext.abort(abortLevel, problem); + } + break; + case Warning : + this.record(problem, unitResult, referenceContext); + break; + } +} +/** + * Standard problem handling API, the actual severity (warning/error/ignore) is deducted + * from the problem ID and the current compiler options. + */ +public void handle( + int problemId, + String[] problemArguments, + String[] messageArguments, + int problemStartPosition, + int problemEndPosition, + ReferenceContext referenceContext, + CompilationResult unitResult) { + + this.handle( + problemId, + problemArguments, + messageArguments, + this.computeSeverity(problemId), // severity inferred using the ID + problemStartPosition, + problemEndPosition, + referenceContext, + unitResult); +} +public void record(IProblem problem, CompilationResult unitResult, ReferenceContext referenceContext) { + unitResult.record(problem, referenceContext); +} +/** + * Search the line number corresponding to a specific position + */ +public static final int searchLineNumber(int[] startLineIndexes, int position) { + if (startLineIndexes == null) + return 1; + int length = startLineIndexes.length; + if (length == 0) + return 1; + int g = 0, d = length - 1; + int m = 0; + while (g <= d) { + m = (g + d) /2; + if (position < startLineIndexes[m]) { + d = m-1; + } else if (position > startLineIndexes[m]) { + g = m+1; + } else { + return m + 1; + } + } + if (position < startLineIndexes[m]) { + return m+1; + } + return m+2; +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java b/src/java/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java new file mode 100644 index 0000000..ba31625 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java @@ -0,0 +1,4096 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.problem; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.core.compiler.IProblem; +import org.eclipse.jdt.internal.compiler.*; +import org.eclipse.jdt.internal.compiler.ast.*; +import org.eclipse.jdt.internal.compiler.env.IConstants; +import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; +import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; +import org.eclipse.jdt.internal.compiler.lookup.*; +import org.eclipse.jdt.internal.compiler.parser.*; +import org.eclipse.jdt.internal.compiler.util.Util; + +public class ProblemReporter extends ProblemHandler implements ProblemReasons { + + public ReferenceContext referenceContext; + +public ProblemReporter(IErrorHandlingPolicy policy, CompilerOptions options, IProblemFactory problemFactory) { + super(policy, options, problemFactory); +} +public void abortDueToInternalError(String errorMessage) { + String[] arguments = new String[] {errorMessage}; + this.handle( + IProblem.Unclassified, + arguments, + arguments, + Error | Abort, + 0, + 0); +} +public void abortDueToInternalError(String errorMessage, ASTNode location) { + String[] arguments = new String[] {errorMessage}; + this.handle( + IProblem.Unclassified, + arguments, + arguments, + Error | Abort, + location.sourceStart, + location.sourceEnd); +} +public void abstractMethodCannotBeOverridden(SourceTypeBinding type, MethodBinding concreteMethod) { + + this.handle( + // %1 must be abstract since it cannot override the inherited package-private abstract method %2 + IProblem.AbstractMethodCannotBeOverridden, + new String[] { + new String(type.sourceName()), + new String( + CharOperation.concat( + concreteMethod.declaringClass.readableName(), + concreteMethod.readableName(), + '.'))}, + new String[] { + new String(type.sourceName()), + new String( + CharOperation.concat( + concreteMethod.declaringClass.shortReadableName(), + concreteMethod.shortReadableName(), + '.'))}, + type.sourceStart(), + type.sourceEnd()); +} +public void abstractMethodInAbstractClass(SourceTypeBinding type, AbstractMethodDeclaration methodDecl) { + + String[] arguments = new String[] {new String(type.sourceName()), new String(methodDecl.selector)}; + this.handle( + IProblem.AbstractMethodInAbstractClass, + arguments, + arguments, + methodDecl.sourceStart, + methodDecl.sourceEnd); +} +public void abstractMethodMustBeImplemented(SourceTypeBinding type, MethodBinding abstractMethod) { + this.handle( + // Must implement the inherited abstract method %1 + // 8.4.3 - Every non-abstract subclass of an abstract type, A, must provide a concrete implementation of all of A's methods. + IProblem.AbstractMethodMustBeImplemented, + new String[] { + new String( + CharOperation.concat( + abstractMethod.declaringClass.readableName(), + abstractMethod.readableName(), + '.'))}, + new String[] { + new String( + CharOperation.concat( + abstractMethod.declaringClass.shortReadableName(), + abstractMethod.shortReadableName(), + '.'))}, + type.sourceStart(), + type.sourceEnd()); +} +public void abstractMethodNeedingNoBody(AbstractMethodDeclaration method) { + this.handle( + IProblem.BodyForAbstractMethod, + NoArgument, + NoArgument, + method.sourceStart, + method.sourceEnd, + method, + method.compilationResult()); +} +public void alreadyDefinedLabel(char[] labelName, ASTNode location) { + String[] arguments = new String[] {new String(labelName)}; + this.handle( + IProblem.DuplicateLabel, + arguments, + arguments, + location.sourceStart, + location.sourceEnd); +} +public void anonymousClassCannotExtendFinalClass(Expression expression, TypeBinding type) { + this.handle( + IProblem.AnonymousClassCannotExtendFinalClass, + new String[] {new String(type.readableName())}, + new String[] {new String(type.shortReadableName())}, + expression.sourceStart, + expression.sourceEnd); +} +public void argumentTypeCannotBeVoid(SourceTypeBinding type, AbstractMethodDeclaration methodDecl, Argument arg) { + String[] arguments = new String[] {new String(methodDecl.selector), new String(arg.name)}; + this.handle( + IProblem.ArgumentTypeCannotBeVoid, + arguments, + arguments, + methodDecl.sourceStart, + methodDecl.sourceEnd); +} +public void argumentTypeCannotBeVoidArray(SourceTypeBinding type, AbstractMethodDeclaration methodDecl, Argument arg) { + String[] arguments = new String[] {new String(methodDecl.selector), new String(arg.name)}; + this.handle( + IProblem.ArgumentTypeCannotBeVoidArray, + arguments, + arguments, + methodDecl.sourceStart, + methodDecl.sourceEnd); +} +public void argumentTypeProblem(SourceTypeBinding type, AbstractMethodDeclaration methodDecl, Argument arg, TypeBinding expectedType) { + int problemId = expectedType.problemId(); + int id; + switch (problemId) { + case NotFound : // 1 + id = IProblem.ArgumentTypeNotFound; + break; + case NotVisible : // 2 + id = IProblem.ArgumentTypeNotVisible; + break; + case Ambiguous : // 3 + id = IProblem.ArgumentTypeAmbiguous; + break; + case InternalNameProvided : // 4 + id = IProblem.ArgumentTypeInternalNameProvided; + break; + case InheritedNameHidesEnclosingName : // 5 + id = IProblem.ArgumentTypeInheritedNameHidesEnclosingName; + break; + case NoError : // 0 + default : + needImplementation(); // want to fail to see why we were here... + return; + } + this.handle( + id, + new String[] {new String(methodDecl.selector), new String(arg.name), new String(expectedType.readableName())}, + new String[] {new String(methodDecl.selector), new String(arg.name), new String(expectedType.shortReadableName())}, + arg.type.sourceStart, + arg.type.sourceEnd); +} +public void arrayConstantsOnlyInArrayInitializers(int sourceStart, int sourceEnd) { + this.handle( + IProblem.ArrayConstantsOnlyInArrayInitializers, + NoArgument, + NoArgument, + sourceStart, + sourceEnd); +} +public void assignmentHasNoEffect(Assignment assignment, char[] name){ + String[] arguments = new String[] { new String(name) }; + this.handle( + IProblem.AssignmentHasNoEffect, + arguments, + arguments, + assignment.sourceStart, + assignment.sourceEnd); +} +public void attemptToReturnNonVoidExpression(ReturnStatement returnStatement, TypeBinding expectedType) { + this.handle( + IProblem.VoidMethodReturnsValue, + new String[] {new String(expectedType.readableName())}, + new String[] {new String(expectedType.shortReadableName())}, + returnStatement.sourceStart, + returnStatement.sourceEnd); +} +public void attemptToReturnVoidValue(ReturnStatement returnStatement) { + this.handle( + IProblem.MethodReturnsVoid, + NoArgument, + NoArgument, + returnStatement.sourceStart, + returnStatement.sourceEnd); +} +public void bytecodeExceeds64KLimit(AbstractMethodDeclaration location) { + String[] arguments = new String[] {new String(location.selector), parametersAsString(location.binding)}; + if (location.isConstructor()) { + this.handle( + IProblem.BytecodeExceeds64KLimitForConstructor, + arguments, + arguments, + Error | Abort, + location.sourceStart, + location.sourceEnd); + } else { + this.handle( + IProblem.BytecodeExceeds64KLimit, + arguments, + arguments, + Error | Abort, + location.sourceStart, + location.sourceEnd); + } +} +public void bytecodeExceeds64KLimit(TypeDeclaration location) { + this.handle( + IProblem.BytecodeExceeds64KLimitForClinit, + NoArgument, + NoArgument, + Error | Abort, + location.sourceStart, + location.sourceEnd); +} +public void cannotAllocateVoidArray(Expression expression) { + this.handle( + IProblem.CannotAllocateVoidArray, + NoArgument, + NoArgument, + expression.sourceStart, + expression.sourceEnd); +} +public void cannotAssignToFinalField(FieldBinding field, ASTNode location) { + this.handle( + IProblem.FinalFieldAssignment, + new String[] { + (field.declaringClass == null ? "array" : new String(field.declaringClass.readableName())), //$NON-NLS-1$ + new String(field.readableName())}, + new String[] { + (field.declaringClass == null ? "array" : new String(field.declaringClass.shortReadableName())), //$NON-NLS-1$ + new String(field.shortReadableName())}, + location.sourceStart, + location.sourceEnd); +} +public void cannotAssignToFinalLocal(LocalVariableBinding local, ASTNode location) { + String[] arguments = new String[] { new String(local.readableName())}; + this.handle( + IProblem.NonBlankFinalLocalAssignment, + arguments, + arguments, + location.sourceStart, + location.sourceEnd); +} +public void cannotAssignToFinalOuterLocal(LocalVariableBinding local, ASTNode location) { + String[] arguments = new String[] {new String(local.readableName())}; + this.handle( + IProblem.FinalOuterLocalAssignment, + arguments, + arguments, + location.sourceStart, + location.sourceEnd); +} +public void cannotDeclareLocalInterface(char[] interfaceName, int sourceStart, int sourceEnd) { + String[] arguments = new String[] {new String(interfaceName)}; + this.handle( + IProblem.CannotDefineInterfaceInLocalType, + arguments, + arguments, + sourceStart, + sourceEnd); +} +public void cannotDefineDimensionsAndInitializer(ArrayAllocationExpression expresssion) { + this.handle( + IProblem.CannotDefineDimensionExpressionsWithInit, + NoArgument, + NoArgument, + expresssion.sourceStart, + expresssion.sourceEnd); +} +public void cannotDireclyInvokeAbstractMethod(MessageSend messageSend, MethodBinding method) { + this.handle( + IProblem.DirectInvocationOfAbstractMethod, + new String[] {new String(method.declaringClass.readableName()), new String(method.selector), parametersAsString(method)}, + new String[] {new String(method.declaringClass.shortReadableName()), new String(method.selector), parametersAsShortString(method)}, + messageSend.sourceStart, + messageSend.sourceEnd); +} +public void cannotImportPackage(ImportReference importRef) { + String[] arguments = new String[] {CharOperation.toString(importRef.tokens)}; + this.handle( + IProblem.CannotImportPackage, + arguments, + arguments, + importRef.sourceStart, + importRef.sourceEnd); +} +public void cannotInstantiate(TypeReference typeRef, TypeBinding type) { + this.handle( + IProblem.InvalidClassInstantiation, + new String[] {new String(type.readableName())}, + new String[] {new String(type.shortReadableName())}, + typeRef.sourceStart, + typeRef.sourceEnd); +} +public void cannotReferToNonFinalOuterLocal(LocalVariableBinding local, ASTNode location) { + String[] arguments =new String[]{ new String(local.readableName())}; + this.handle( + IProblem.OuterLocalMustBeFinal, + arguments, + arguments, + location.sourceStart, + location.sourceEnd); +} +public void cannotReturnInInitializer(ASTNode location) { + this.handle( + IProblem.CannotReturnInInitializer, + NoArgument, + NoArgument, + location.sourceStart, + location.sourceEnd); +} +public void cannotThrowNull(ThrowStatement statement) { + this.handle( + IProblem.CannotThrowNull, + NoArgument, + NoArgument, + statement.sourceStart, + statement.sourceEnd); +} +public void cannotThrowType(SourceTypeBinding type, AbstractMethodDeclaration methodDecl, TypeReference exceptionType, TypeBinding expectedType) { + this.handle( + IProblem.CannotThrowType, + new String[] {new String(expectedType.readableName())}, + new String[] {new String(expectedType.shortReadableName())}, + exceptionType.sourceStart, + exceptionType.sourceEnd); +} +public void cannotUseSuperInJavaLangObject(ASTNode reference) { + this.handle( + IProblem.ObjectHasNoSuperclass, + NoArgument, + NoArgument, + reference.sourceStart, + reference.sourceEnd); +} +public void cannotUseSuperInCodeSnippet(int start, int end) { + this.handle( + IProblem.CannotUseSuperInCodeSnippet, + NoArgument, + NoArgument, + Error | Abort, + start, + end); +} +public void caseExpressionMustBeConstant(Expression expression) { + this.handle( + IProblem.NonConstantExpression, + NoArgument, + NoArgument, + expression.sourceStart, + expression.sourceEnd); +} +public void classExtendFinalClass(SourceTypeBinding type, TypeReference superclass, TypeBinding expectedType) { + String name = new String(type.sourceName()); + String expectedFullName = new String(expectedType.readableName()); + String expectedShortName = new String(expectedType.shortReadableName()); + if (expectedShortName.equals(name)) expectedShortName = expectedFullName; + this.handle( + IProblem.ClassExtendFinalClass, + new String[] {expectedFullName, name}, + new String[] {expectedShortName, name}, + superclass.sourceStart, + superclass.sourceEnd); +} +public void codeSnippetMissingClass(String missing, int start, int end) { + String[] arguments = new String[]{missing}; + this.handle( + IProblem.CodeSnippetMissingClass, + arguments, + arguments, + Error | Abort, + start, + end); +} +public void codeSnippetMissingMethod(String className, String missingMethod, String argumentTypes, int start, int end) { + String[] arguments = new String[]{ className, missingMethod, argumentTypes }; + this.handle( + IProblem.CodeSnippetMissingMethod, + arguments, + arguments, + Error | Abort, + start, + end); +} +/* + * Given the current configuration, answers which category the problem + * falls into: + * Error | Warning | Ignore + */ +public int computeSeverity(int problemId){ + + // severity can have been preset on the problem +// if ((problem.severity & Fatal) != 0){ +// return Error; +// } + + // if not then check whether it is a configurable problem + switch(problemId){ + + case IProblem.MaskedCatch : + return this.options.getSeverity(CompilerOptions.MaskedCatchBlock); + + case IProblem.UnusedImport : + return this.options.getSeverity(CompilerOptions.UnusedImport); + + case IProblem.MethodButWithConstructorName : + return this.options.getSeverity(CompilerOptions.MethodWithConstructorName); + + case IProblem.OverridingNonVisibleMethod : + return this.options.getSeverity(CompilerOptions.OverriddenPackageDefaultMethod); + + case IProblem.IncompatibleReturnTypeForNonInheritedInterfaceMethod : + case IProblem.IncompatibleExceptionInThrowsClauseForNonInheritedInterfaceMethod : + return this.options.getSeverity(CompilerOptions.IncompatibleNonInheritedInterfaceMethod); + + case IProblem.OverridingDeprecatedMethod : + case IProblem.UsingDeprecatedType : + case IProblem.UsingDeprecatedMethod : + case IProblem.UsingDeprecatedConstructor : + case IProblem.UsingDeprecatedField : + return this.options.getSeverity(CompilerOptions.UsingDeprecatedAPI); + + case IProblem.LocalVariableIsNeverUsed : + return this.options.getSeverity(CompilerOptions.UnusedLocalVariable); + + case IProblem.ArgumentIsNeverUsed : + return this.options.getSeverity(CompilerOptions.UnusedArgument); + + case IProblem.NoImplicitStringConversionForCharArrayExpression : + return this.options.getSeverity(CompilerOptions.NoImplicitStringConversion); + + case IProblem.NeedToEmulateFieldReadAccess : + case IProblem.NeedToEmulateFieldWriteAccess : + case IProblem.NeedToEmulateMethodAccess : + case IProblem.NeedToEmulateConstructorAccess : + return this.options.getSeverity(CompilerOptions.AccessEmulation); + + case IProblem.NonExternalizedStringLiteral : + return this.options.getSeverity(CompilerOptions.NonExternalizedString); + + case IProblem.UseAssertAsAnIdentifier : + return this.options.getSeverity(CompilerOptions.AssertUsedAsAnIdentifier); + + case IProblem.NonStaticAccessToStaticMethod : + case IProblem.NonStaticAccessToStaticField : + return this.options.getSeverity(CompilerOptions.NonStaticAccessToStatic); + + case IProblem.IndirectAccessToStaticMethod : + case IProblem.IndirectAccessToStaticField : + case IProblem.IndirectAccessToStaticType : + return this.options.getSeverity(CompilerOptions.IndirectStaticAccess); + + case IProblem.AssignmentHasNoEffect: + return this.options.getSeverity(CompilerOptions.NoEffectAssignment); + + case IProblem.UnusedPrivateConstructor: + case IProblem.UnusedPrivateMethod: + case IProblem.UnusedPrivateField: + case IProblem.UnusedPrivateType: + return this.options.getSeverity(CompilerOptions.UnusedPrivateMember); + + case IProblem.Task : + return Warning; + + case IProblem.LocalVariableHidingLocalVariable: + case IProblem.LocalVariableHidingField: + case IProblem.ArgumentHidingLocalVariable: + case IProblem.ArgumentHidingField: + return this.options.getSeverity(CompilerOptions.LocalVariableHiding); + + case IProblem.FieldHidingLocalVariable: + case IProblem.FieldHidingField: + return this.options.getSeverity(CompilerOptions.FieldHiding); + + case IProblem.PossibleAccidentalBooleanAssignment: + return this.options.getSeverity(CompilerOptions.AccidentalBooleanAssign); + + case IProblem.SuperfluousSemicolon: + case IProblem.EmptyControlFlowStatement: + return this.options.getSeverity(CompilerOptions.EmptyStatement); + + case IProblem.UndocumentedEmptyBlock: + return this.options.getSeverity(CompilerOptions.UndocumentedEmptyBlock); + + case IProblem.UnnecessaryCast: + case IProblem.UnnecessaryArgumentCast: + case IProblem.UnnecessaryInstanceof: + return this.options.getSeverity(CompilerOptions.UnnecessaryTypeCheck); + + case IProblem.FinallyMustCompleteNormally: + return this.options.getSeverity(CompilerOptions.FinallyBlockNotCompleting); + + case IProblem.UnusedMethodDeclaredThrownException: + case IProblem.UnusedConstructorDeclaredThrownException: + return this.options.getSeverity(CompilerOptions.UnusedDeclaredThrownException); + + case IProblem.UnqualifiedFieldAccess: + return this.options.getSeverity(CompilerOptions.UnqualifiedFieldAccess); + + case IProblem.UnnecessaryElse: + return this.options.getSeverity(CompilerOptions.UnnecessaryElse); + + /* + * Javadoc syntax errors + */ + // Javadoc explicit IDs + case IProblem.JavadocUnexpectedTag: + case IProblem.JavadocDuplicateReturnTag: + case IProblem.JavadocInvalidThrowsClass: + case IProblem.JavadocInvalidSeeReference: + case IProblem.JavadocMalformedSeeReference: + case IProblem.JavadocInvalidSeeHref: + case IProblem.JavadocInvalidSeeArgs: + case IProblem.JavadocInvalidTag: + case IProblem.JavadocUnterminatedInlineTag: + if (this.options.docCommentSupport) { + return this.options.getSeverity(CompilerOptions.InvalidJavadoc); + } else { + return ProblemSeverities.Ignore; + } + + /* + * Javadoc tags resolved references errors + */ + case IProblem.JavadocInvalidParamName: + case IProblem.JavadocDuplicateParamName: + case IProblem.JavadocMissingParamName: + case IProblem.JavadocInvalidThrowsClassName: + case IProblem.JavadocDuplicateThrowsClassName: + case IProblem.JavadocMissingThrowsClassName: + case IProblem.JavadocMissingSeeReference: + case IProblem.JavadocUsingDeprecatedField: + case IProblem.JavadocUsingDeprecatedConstructor: + case IProblem.JavadocUsingDeprecatedMethod: + case IProblem.JavadocUsingDeprecatedType: + case IProblem.JavadocUndefinedField: + case IProblem.JavadocNotVisibleField: + case IProblem.JavadocAmbiguousField: + case IProblem.JavadocUndefinedConstructor: + case IProblem.JavadocNotVisibleConstructor: + case IProblem.JavadocAmbiguousConstructor: + case IProblem.JavadocUndefinedMethod: + case IProblem.JavadocNotVisibleMethod: + case IProblem.JavadocAmbiguousMethod: + case IProblem.JavadocAmbiguousMethodReference: + case IProblem.JavadocParameterMismatch: + case IProblem.JavadocUndefinedType: + case IProblem.JavadocNotVisibleType: + case IProblem.JavadocAmbiguousType: + case IProblem.JavadocInternalTypeNameProvided: + case IProblem.JavadocNoMessageSendOnArrayType: + case IProblem.JavadocNoMessageSendOnBaseType: + case IProblem.JavadocInheritedMethodHidesEnclosingName: + case IProblem.JavadocInheritedFieldHidesEnclosingName: + case IProblem.JavadocInheritedNameHidesEnclosingTypeName: + if (this.options.docCommentSupport && this.options.reportInvalidJavadocTags) { + return this.options.getSeverity(CompilerOptions.InvalidJavadoc); + } else { + return ProblemSeverities.Ignore; + } + + /* + * Javadoc missing tags errors + */ + case IProblem.JavadocMissingParamTag: + case IProblem.JavadocMissingReturnTag: + case IProblem.JavadocMissingThrowsTag: + if (this.options.docCommentSupport) { + return this.options.getSeverity(CompilerOptions.MissingJavadocTags); + } else { + return ProblemSeverities.Ignore; + } + + /* + * Missing Javadoc errors + */ + case IProblem.JavadocMissing: + if (this.options.docCommentSupport) { + return this.options.getSeverity(CompilerOptions.MissingJavadocComments); + } else { + return ProblemSeverities.Ignore; + } + + // by default problems are errors. + default: + return Error; + } +} +public void conditionalArgumentsIncompatibleTypes(ConditionalExpression expression, TypeBinding trueType, TypeBinding falseType) { + this.handle( + IProblem.IncompatibleTypesInConditionalOperator, + new String[] {new String(trueType.readableName()), new String(falseType.readableName())}, + new String[] {new String(trueType.sourceName()), new String(falseType.sourceName())}, + expression.sourceStart, + expression.sourceEnd); +} +public void conflictingImport(ImportReference importRef) { + String[] arguments = new String[] {CharOperation.toString(importRef.tokens)}; + this.handle( + IProblem.ConflictingImport, + arguments, + arguments, + importRef.sourceStart, + importRef.sourceEnd); +} +public void constantOutOfFormat(NumberLiteral literal) { + // the literal is not in a correct format + // this code is called on IntLiteral and LongLiteral + // example 000811 ...the 8 is uncorrect. + + if ((literal instanceof LongLiteral) || (literal instanceof IntLiteral)) { + char[] source = literal.source(); + try { + final String Radix; + final int radix; + if ((source[1] == 'x') || (source[1] == 'X')) { + radix = 16; + Radix = "Hex"; //$NON-NLS-1$ + } else { + radix = 8; + Radix = "Octal"; //$NON-NLS-1$ + } + //look for the first digit that is incorrect + int place = -1; + label : for (int i = radix == 8 ? 1 : 2; i < source.length; i++) { + if (Character.digit(source[i], radix) == -1) { + place = i; + break label; + } + } + String[] arguments = new String[] { + new String(literal.literalType(null).readableName()), // numeric literals do not need scope to reach type + Radix + " " + new String(source) + " (digit " + new String(new char[] {source[place]}) + ")"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + + this.handle( + IProblem.NumericValueOutOfRange, + arguments, + arguments, + literal.sourceStart, + literal.sourceEnd); + return; + } catch (IndexOutOfBoundsException ex) { + // should never happen + } + + // just in case .... use a predefined error.. + // we should never come here...(except if the code changes !) + this.constantOutOfRange(literal, literal.literalType(null)); // numeric literals do not need scope to reach type + } +} +public void constantOutOfRange(Literal literal, TypeBinding literalType) { + String[] arguments = new String[] {new String(literalType.readableName()), new String(literal.source())}; + this.handle( + IProblem.NumericValueOutOfRange, + arguments, + arguments, + literal.sourceStart, + literal.sourceEnd); +} +public void deprecatedField(FieldBinding field, ASTNode location) { + this.handle( + IProblem.UsingDeprecatedField, + new String[] {new String(field.declaringClass.readableName()), new String(field.name)}, + new String[] {new String(field.declaringClass.shortReadableName()), new String(field.name)}, + location.sourceStart, + location.sourceEnd); +} +public void deprecatedMethod(MethodBinding method, ASTNode location) { + if (method.isConstructor()) { + this.handle( + IProblem.UsingDeprecatedConstructor, + new String[] {new String(method.declaringClass.readableName()), parametersAsString(method)}, + new String[] {new String(method.declaringClass.shortReadableName()), parametersAsShortString(method)}, + location.sourceStart, + location.sourceEnd); + } else { + this.handle( + IProblem.UsingDeprecatedMethod, + new String[] {new String(method.declaringClass.readableName()), new String(method.selector), parametersAsString(method)}, + new String[] {new String(method.declaringClass.shortReadableName()), new String(method.selector), parametersAsShortString(method)}, + location.sourceStart, + location.sourceEnd); + } +} +public void deprecatedType(TypeBinding type, ASTNode location) { + if (location == null) return; // 1G828DN - no type ref for synthetic arguments + this.handle( + IProblem.UsingDeprecatedType, + new String[] {new String(type.readableName())}, + new String[] {new String(type.shortReadableName())}, + location.sourceStart, + location.sourceEnd); +} +public void duplicateCase(CaseStatement caseStatement) { + this.handle( + IProblem.DuplicateCase, + NoArgument, + NoArgument, + caseStatement.sourceStart, + caseStatement.sourceEnd); +} +public void duplicateDefaultCase(ASTNode statement) { + this.handle( + IProblem.DuplicateDefaultCase, + NoArgument, + NoArgument, + statement.sourceStart, + statement.sourceEnd); +} +public void duplicateFieldInType(SourceTypeBinding type, FieldDeclaration fieldDecl) { + this.handle( + IProblem.DuplicateField, + new String[] {new String(type.sourceName()), new String(fieldDecl.name)}, + new String[] {new String(type.shortReadableName()), new String(fieldDecl.name)}, + fieldDecl.sourceStart, + fieldDecl.sourceEnd); +} +public void duplicateImport(ImportReference importRef) { + String[] arguments = new String[] {CharOperation.toString(importRef.tokens)}; + this.handle( + IProblem.DuplicateImport, + arguments, + arguments, + importRef.sourceStart, + importRef.sourceEnd); +} +public void duplicateInitializationOfBlankFinalField(FieldBinding field, Reference reference) { + String[] arguments = new String[]{ new String(field.readableName())}; + this.handle( + IProblem.DuplicateBlankFinalFieldInitialization, + arguments, + arguments, + reference.sourceStart, + reference.sourceEnd); +} +public void duplicateInitializationOfFinalLocal(LocalVariableBinding local, ASTNode location) { + String[] arguments = new String[] { new String(local.readableName())}; + this.handle( + IProblem.DuplicateFinalLocalInitialization, + arguments, + arguments, + location.sourceStart, + location.sourceEnd); +} +public void duplicateMethodInType(SourceTypeBinding type, AbstractMethodDeclaration methodDecl) { + String[] arguments = new String[] {new String(methodDecl.selector), new String(type.sourceName())}; + this.handle( + IProblem.DuplicateMethod, + arguments, + arguments, + methodDecl.sourceStart, + methodDecl.sourceEnd); +} +public void duplicateModifierForField(ReferenceBinding type, FieldDeclaration fieldDecl) { +/* to highlight modifiers use: + this.handle( + new Problem( + DuplicateModifierForField, + new String[] {new String(fieldDecl.name)}, + fieldDecl.modifiers.sourceStart, + fieldDecl.modifiers.sourceEnd)); +*/ + String[] arguments = new String[] {new String(fieldDecl.name)}; + this.handle( + IProblem.DuplicateModifierForField, + arguments, + arguments, + fieldDecl.sourceStart, + fieldDecl.sourceEnd); +} +public void duplicateModifierForMethod(ReferenceBinding type, AbstractMethodDeclaration methodDecl) { + this.handle( + IProblem.DuplicateModifierForMethod, + new String[] {new String(type.sourceName()), new String(methodDecl.selector)}, + new String[] {new String(type.shortReadableName()), new String(methodDecl.selector)}, + methodDecl.sourceStart, + methodDecl.sourceEnd); +} +public void duplicateModifierForType(SourceTypeBinding type) { + String[] arguments = new String[] {new String(type.sourceName())}; + this.handle( + IProblem.DuplicateModifierForType, + arguments, + arguments, + type.sourceStart(), + type.sourceEnd()); +} +public void duplicateModifierForVariable(LocalDeclaration localDecl, boolean complainForArgument) { + String[] arguments = new String[] {new String(localDecl.name)}; + this.handle( + complainForArgument + ? IProblem.DuplicateModifierForArgument + : IProblem.DuplicateModifierForVariable, + arguments, + arguments, + localDecl.sourceStart, + localDecl.sourceEnd); +} +public void duplicateNestedType(TypeDeclaration typeDecl) { + String[] arguments = new String[] {new String(typeDecl.name)}; + this.handle( + IProblem.DuplicateNestedType, + arguments, + arguments, + typeDecl.sourceStart, + typeDecl.sourceEnd); +} +public void duplicateSuperinterface(SourceTypeBinding type, TypeDeclaration typeDecl, ReferenceBinding superType) { + this.handle( + IProblem.DuplicateSuperInterface, + new String[] { + new String(superType.readableName()), + new String(type.sourceName())}, + new String[] { + new String(superType.shortReadableName()), + new String(type.sourceName())}, + typeDecl.sourceStart, + typeDecl.sourceEnd); +} +public void duplicateTypes(CompilationUnitDeclaration compUnitDecl, TypeDeclaration typeDecl) { + String[] arguments = new String[] {new String(compUnitDecl.getFileName()), new String(typeDecl.name)}; + this.referenceContext = typeDecl; // report the problem against the type not the entire compilation unit + this.handle( + IProblem.DuplicateTypes, + arguments, + arguments, + typeDecl.sourceStart, + typeDecl.sourceEnd, + compUnitDecl.compilationResult); +} +public void emptyControlFlowStatement(int sourceStart, int sourceEnd) { + this.handle( + IProblem.EmptyControlFlowStatement, + NoArgument, + NoArgument, + sourceStart, + sourceEnd); +} +public void errorNoMethodFor(MessageSend messageSend, TypeBinding recType, TypeBinding[] params) { + StringBuffer buffer = new StringBuffer(); + StringBuffer shortBuffer = new StringBuffer(); + for (int i = 0, length = params.length; i < length; i++) { + if (i != 0){ + buffer.append(", "); //$NON-NLS-1$ + shortBuffer.append(", "); //$NON-NLS-1$ + } + buffer.append(new String(params[i].readableName())); + shortBuffer.append(new String(params[i].shortReadableName())); + } + + int id = recType.isArrayType() ? IProblem.NoMessageSendOnArrayType : IProblem.NoMessageSendOnBaseType; + /* + if ((messageSend.bits & ASTNode.InsideJavadoc) != 0) { + id |= IProblem.Javadoc; + if (!reportInvalidJavadocTagsVisibility()) return; + } + */ + this.handle( + id, + new String[] {new String(recType.readableName()), new String(messageSend.selector), buffer.toString()}, + new String[] {new String(recType.shortReadableName()), new String(messageSend.selector), shortBuffer.toString()}, + messageSend.sourceStart, + messageSend.sourceEnd); +} +public void errorThisSuperInStatic(ASTNode reference) { + String[] arguments = new String[] {reference.isSuper() ? "super" : "this"}; //$NON-NLS-2$ //$NON-NLS-1$ + this.handle( + IProblem.ThisInStaticContext, + arguments, + arguments, + reference.sourceStart, + reference.sourceEnd); +} +public void exceptionTypeProblem(SourceTypeBinding type, AbstractMethodDeclaration methodDecl, TypeReference exceptionType, TypeBinding expectedType) { + int problemId = expectedType.problemId(); + int id; + switch (problemId) { + case NotFound : // 1 + id = IProblem.ExceptionTypeNotFound; + break; + case NotVisible : // 2 + id = IProblem.ExceptionTypeNotVisible; + break; + case Ambiguous : // 3 + id = IProblem.ExceptionTypeAmbiguous; + break; + case InternalNameProvided : // 4 + id = IProblem.ExceptionTypeInternalNameProvided; + break; + case InheritedNameHidesEnclosingName : // 5 + id = IProblem.ExceptionTypeInheritedNameHidesEnclosingName; + break; + case NoError : // 0 + default : + needImplementation(); // want to fail to see why we were here... + return; + } + this.handle( + id, + new String[] {new String(methodDecl.selector), new String(expectedType.readableName())}, + new String[] {new String(methodDecl.selector), new String(expectedType.shortReadableName())}, + exceptionType.sourceStart, + exceptionType.sourceEnd); +} +public void expressionShouldBeAVariable(Expression expression) { + this.handle( + IProblem.ExpressionShouldBeAVariable, + NoArgument, + NoArgument, + expression.sourceStart, + expression.sourceEnd); +} +public void fieldHiding(FieldDeclaration fieldDecl, Binding hiddenVariable) { + FieldBinding field = fieldDecl.binding; + if (CharOperation.equals(TypeConstants.SERIALVERSIONUID, field.name) + && field.isStatic() + && field.isFinal() + && BaseTypes.LongBinding == field.type) { + return; // do not report unused serialVersionUID field + } + if (CharOperation.equals(TypeConstants.SERIALPERSISTENTFIELDS, field.name) + && field.isStatic() + && field.isFinal() + && field.type.dimensions() == 1 + && CharOperation.equals(TypeConstants.CharArray_JAVA_IO_OBJECTSTREAMFIELD, field.type.leafComponentType().readableName())) { + return; // do not report unused serialPersistentFields field + } + + if (hiddenVariable instanceof LocalVariableBinding) { + this.handle( + IProblem.FieldHidingLocalVariable, + new String[] {new String(field.declaringClass.readableName()), new String(field.name) }, + new String[] {new String(field.declaringClass.shortReadableName()), new String(field.name) }, + fieldDecl.sourceStart, + fieldDecl.sourceEnd); + } else if (hiddenVariable instanceof FieldBinding) { + FieldBinding hiddenField = (FieldBinding) hiddenVariable; + this.handle( + IProblem.FieldHidingField, + new String[] {new String(field.declaringClass.readableName()), new String(field.name) , new String(hiddenField.declaringClass.readableName()) }, + new String[] {new String(field.declaringClass.shortReadableName()), new String(field.name) , new String(hiddenField.declaringClass.shortReadableName()) }, + fieldDecl.sourceStart, + fieldDecl.sourceEnd); + } +} +private int fieldLocation(FieldBinding field, ASTNode node) { + if (node instanceof QualifiedNameReference) { + QualifiedNameReference ref = (QualifiedNameReference) node; + FieldBinding[] bindings = ref.otherBindings; + if (bindings != null) + for (int i = bindings.length; --i >= 0;) + if (bindings[i] == field) + return (int) ref.sourcePositions[i + 1]; // first position is for the primary field + } + return node.sourceEnd; +} +public void fieldsOrThisBeforeConstructorInvocation(ThisReference reference) { + this.handle( + IProblem.ThisSuperDuringConstructorInvocation, + NoArgument, + NoArgument, + reference.sourceStart, + reference.sourceEnd); +} +public void fieldTypeProblem(SourceTypeBinding type, FieldDeclaration fieldDecl, TypeBinding expectedType) { + int problemId = expectedType.problemId(); + int id; + switch (problemId) { + case NotFound : // 1 + id = IProblem.FieldTypeNotFound; + break; + case NotVisible : // 2 + id = IProblem.FieldTypeNotVisible; + break; + case Ambiguous : // 3 + id = IProblem.FieldTypeAmbiguous; + break; + case InternalNameProvided : // 4 + id = IProblem.FieldTypeInternalNameProvided; + break; + case InheritedNameHidesEnclosingName : // 5 + id = IProblem.FieldTypeInheritedNameHidesEnclosingName; + break; + case NoError : // 0 + default : + needImplementation(); // want to fail to see why we were here... + return; + } + this.handle( + id, + new String[] {new String(fieldDecl.name), new String(type.sourceName()), new String(expectedType.readableName())}, + new String[] {new String(fieldDecl.name), new String(type.sourceName()), new String(expectedType.shortReadableName())}, + fieldDecl.type.sourceStart, + fieldDecl.type.sourceEnd); +} +public void finallyMustCompleteNormally(Block finallyBlock) { + this.handle( + IProblem.FinallyMustCompleteNormally, + NoArgument, + NoArgument, + finallyBlock.sourceStart, + finallyBlock.sourceEnd); +} +public void finalMethodCannotBeOverridden(MethodBinding currentMethod, MethodBinding inheritedMethod) { + this.handle( + // Cannot override the final method from %1 + // 8.4.3.3 - Final methods cannot be overridden or hidden. + IProblem.FinalMethodCannotBeOverridden, + new String[] {new String(inheritedMethod.declaringClass.readableName())}, + new String[] {new String(inheritedMethod.declaringClass.shortReadableName())}, + currentMethod.sourceStart(), + currentMethod.sourceEnd()); +} +public void forwardReference(Reference reference, int indexInQualification, TypeBinding type) { + this.handle( + IProblem.ReferenceToForwardField, + NoArgument, + NoArgument, + reference.sourceStart, + reference.sourceEnd); +} +// use this private API when the compilation unit result can be found through the +// reference context. Otherwise, use the other API taking a problem and a compilation result +// as arguments +private void handle( + int problemId, + String[] problemArguments, + String[] messageArguments, + int problemStartPosition, + int problemEndPosition){ + + this.handle( + problemId, + problemArguments, + messageArguments, + problemStartPosition, + problemEndPosition, + this.referenceContext, + this.referenceContext == null ? null : this.referenceContext.compilationResult()); + this.referenceContext = null; +} +// use this private API when the compilation unit result can be found through the +// reference context. Otherwise, use the other API taking a problem and a compilation result +// as arguments +private void handle( + int problemId, + String[] problemArguments, + String[] messageArguments, + int severity, + int problemStartPosition, + int problemEndPosition){ + + this.handle( + problemId, + problemArguments, + messageArguments, + severity, + problemStartPosition, + problemEndPosition, + this.referenceContext, + this.referenceContext == null ? null : this.referenceContext.compilationResult()); + this.referenceContext = null; +} +// use this private API when the compilation unit result cannot be found through the +// reference context. + +private void handle( + int problemId, + String[] problemArguments, + String[] messageArguments, + int problemStartPosition, + int problemEndPosition, + CompilationResult unitResult){ + + this.handle( + problemId, + problemArguments, + messageArguments, + problemStartPosition, + problemEndPosition, + this.referenceContext, + unitResult); + this.referenceContext = null; +} +public void hiddenCatchBlock(ReferenceBinding exceptionType, ASTNode location) { + this.handle( + IProblem.MaskedCatch, + new String[] { + new String(exceptionType.readableName()), + }, + new String[] { + new String(exceptionType.shortReadableName()), + }, + location.sourceStart, + location.sourceEnd); +} +public void hidingEnclosingType(TypeDeclaration typeDecl) { + String[] arguments = new String[] {new String(typeDecl.name)}; + this.handle( + IProblem.HidingEnclosingType, + arguments, + arguments, + typeDecl.sourceStart, + typeDecl.sourceEnd); +} +public void hierarchyCircularity(SourceTypeBinding sourceType, ReferenceBinding superType, TypeReference reference) { + int start = 0; + int end = 0; + String typeName = ""; //$NON-NLS-1$ + String shortTypeName = ""; //$NON-NLS-1$ + + if (reference == null) { // can only happen when java.lang.Object is busted + start = sourceType.sourceStart(); + end = sourceType.sourceEnd(); + typeName = new String(superType.readableName()); + shortTypeName = new String(superType.sourceName()); + } else { + start = reference.sourceStart; + end = reference.sourceEnd; + char[][] qName = reference.getTypeName(); + typeName = CharOperation.toString(qName); + shortTypeName = new String(qName[qName.length-1]); + } + + if (sourceType == superType) + this.handle( + IProblem.HierarchyCircularitySelfReference, + new String[] {new String(sourceType.sourceName()), typeName}, + new String[] {new String(sourceType.sourceName()), shortTypeName}, + start, + end); + else + this.handle( + IProblem.HierarchyCircularity, + new String[] {new String(sourceType.sourceName()), typeName}, + new String[] {new String(sourceType.sourceName()), shortTypeName}, + start, + end); +} +public void hierarchyHasProblems(SourceTypeBinding type) { + String[] arguments = new String[] {new String(type.sourceName())}; + this.handle( + IProblem.HierarchyHasProblems, + arguments, + arguments, + type.sourceStart(), + type.sourceEnd()); +} +public void illegalAbstractModifierCombinationForMethod(ReferenceBinding type, AbstractMethodDeclaration methodDecl) { + String[] arguments = new String[] {new String(type.sourceName()), new String(methodDecl.selector)}; + this.handle( + IProblem.IllegalAbstractModifierCombinationForMethod, + arguments, + arguments, + methodDecl.sourceStart, + methodDecl.sourceEnd); +} +public void illegalModifierCombinationFinalAbstractForClass(SourceTypeBinding type) { + String[] arguments = new String[] {new String(type.sourceName())}; + this.handle( + IProblem.IllegalModifierCombinationFinalAbstractForClass, + arguments, + arguments, + type.sourceStart(), + type.sourceEnd()); +} +public void illegalModifierCombinationFinalVolatileForField(ReferenceBinding type, FieldDeclaration fieldDecl) { + String[] arguments = new String[] {new String(fieldDecl.name)}; + + this.handle( + IProblem.IllegalModifierCombinationFinalVolatileForField, + arguments, + arguments, + fieldDecl.sourceStart, + fieldDecl.sourceEnd); +} + +public void illegalModifierForClass(SourceTypeBinding type) { + String[] arguments = new String[] {new String(type.sourceName())}; + this.handle( + IProblem.IllegalModifierForClass, + arguments, + arguments, + type.sourceStart(), + type.sourceEnd()); +} +public void illegalModifierForField(ReferenceBinding type, FieldDeclaration fieldDecl) { + String[] arguments = new String[] {new String(fieldDecl.name)}; + this.handle( + IProblem.IllegalModifierForField, + arguments, + arguments, + fieldDecl.sourceStart, + fieldDecl.sourceEnd); +} +public void illegalModifierForInterface(SourceTypeBinding type) { + String[] arguments = new String[] {new String(type.sourceName())}; + this.handle( + IProblem.IllegalModifierForInterface, + arguments, + arguments, + type.sourceStart(), + type.sourceEnd()); +} +public void illegalModifierForInterfaceField(ReferenceBinding type, FieldDeclaration fieldDecl) { + String[] arguments = new String[] {new String(fieldDecl.name)}; + this.handle( + IProblem.IllegalModifierForInterfaceField, + arguments, + arguments, + fieldDecl.sourceStart, + fieldDecl.sourceEnd); +} +public void illegalModifierForInterfaceMethod(ReferenceBinding type, AbstractMethodDeclaration methodDecl) { + String[] arguments = new String[] {new String(type.sourceName()), new String(methodDecl.selector)}; + this.handle( + IProblem.IllegalModifierForInterfaceMethod, + arguments, + arguments, + methodDecl.sourceStart, + methodDecl.sourceEnd); +} +public void illegalModifierForLocalClass(SourceTypeBinding type) { + String[] arguments = new String[] {new String(type.sourceName())}; + this.handle( + IProblem.IllegalModifierForLocalClass, + arguments, + arguments, + type.sourceStart(), + type.sourceEnd()); +} +public void illegalModifierForMemberClass(SourceTypeBinding type) { + String[] arguments = new String[] {new String(type.sourceName())}; + this.handle( + IProblem.IllegalModifierForMemberClass, + arguments, + arguments, + type.sourceStart(), + type.sourceEnd()); +} +public void illegalModifierForMemberInterface(SourceTypeBinding type) { + String[] arguments = new String[] {new String(type.sourceName())}; + this.handle( + IProblem.IllegalModifierForMemberInterface, + arguments, + arguments, + type.sourceStart(), + type.sourceEnd()); +} +public void illegalModifierForMethod(ReferenceBinding type, AbstractMethodDeclaration methodDecl) { + String[] arguments = new String[] {new String(type.sourceName()), new String(methodDecl.selector)}; + this.handle( + IProblem.IllegalModifierForMethod, + arguments, + arguments, + methodDecl.sourceStart, + methodDecl.sourceEnd); +} +public void illegalModifierForVariable(LocalDeclaration localDecl, boolean complainAsArgument) { + String[] arguments = new String[] {new String(localDecl.name)}; + this.handle( + complainAsArgument + ? IProblem.IllegalModifierForArgument + : IProblem.IllegalModifierForVariable, + arguments, + arguments, + localDecl.sourceStart, + localDecl.sourceEnd); +} +public void illegalPrimitiveOrArrayTypeForEnclosingInstance(TypeBinding enclosingType, ASTNode location) { + this.handle( + IProblem.IllegalPrimitiveOrArrayTypeForEnclosingInstance, + new String[] {new String(enclosingType.readableName())}, + new String[] {new String(enclosingType.shortReadableName())}, + location.sourceStart, + location.sourceEnd); +} +public void illegalStaticModifierForMemberType(SourceTypeBinding type) { + String[] arguments = new String[] {new String(type.sourceName())}; + this.handle( + IProblem.IllegalStaticModifierForMemberType, + arguments, + arguments, + type.sourceStart(), + type.sourceEnd()); +} +public void illegalVisibilityModifierCombinationForField(ReferenceBinding type, FieldDeclaration fieldDecl) { + String[] arguments = new String[] {new String(fieldDecl.name)}; + this.handle( + IProblem.IllegalVisibilityModifierCombinationForField, + arguments, + arguments, + fieldDecl.sourceStart, + fieldDecl.sourceEnd); +} +public void illegalVisibilityModifierCombinationForMemberType(SourceTypeBinding type) { + String[] arguments = new String[] {new String(type.sourceName())}; + this.handle( + IProblem.IllegalVisibilityModifierCombinationForMemberType, + arguments, + arguments, + type.sourceStart(), + type.sourceEnd()); +} +public void illegalVisibilityModifierCombinationForMethod(ReferenceBinding type, AbstractMethodDeclaration methodDecl) { + String[] arguments = new String[] {new String(type.sourceName()), new String(methodDecl.selector)}; + this.handle( + IProblem.IllegalVisibilityModifierCombinationForMethod, + arguments, + arguments, + methodDecl.sourceStart, + methodDecl.sourceEnd); +} +public void illegalVisibilityModifierForInterfaceMemberType(SourceTypeBinding type) { + String[] arguments = new String[] {new String(type.sourceName())}; + this.handle( + IProblem.IllegalVisibilityModifierForInterfaceMemberType, + arguments, + arguments, + type.sourceStart(), + type.sourceEnd()); +} +public void illegalVoidExpression(ASTNode location) { + this.handle( + IProblem.InvalidVoidExpression, + NoArgument, + NoArgument, + location.sourceStart, + location.sourceEnd); +} +public void importProblem(ImportReference importRef, Binding expectedImport) { + int problemId = expectedImport.problemId(); + int id; + switch (problemId) { + case NotFound : // 1 + id = IProblem.ImportNotFound; + break; + case NotVisible : // 2 + id = IProblem.ImportNotVisible; + break; + case Ambiguous : // 3 + id = IProblem.ImportAmbiguous; + break; + case InternalNameProvided : // 4 + id = IProblem.ImportInternalNameProvided; + break; + case InheritedNameHidesEnclosingName : // 5 + id = IProblem.ImportInheritedNameHidesEnclosingName; + break; + case NoError : // 0 + default : + needImplementation(); // want to fail to see why we were here... + return; + } + char[][] tokens = expectedImport instanceof ProblemReferenceBinding + ? ((ProblemReferenceBinding) expectedImport).compoundName + : importRef.tokens; + String[] arguments = new String[]{CharOperation.toString(tokens)}; + this.handle(id, arguments, arguments, importRef.sourceStart, (int) importRef.sourcePositions[tokens.length - 1]); +} +public void incompatibleExceptionInThrowsClause(SourceTypeBinding type, MethodBinding currentMethod, MethodBinding inheritedMethod, ReferenceBinding exceptionType) { + if (type == currentMethod.declaringClass) { + int id; + if (currentMethod.declaringClass.isInterface() + && !inheritedMethod.isPublic()){ // interface inheriting Object protected method + id = IProblem.IncompatibleExceptionInThrowsClauseForNonInheritedInterfaceMethod; + } else { + id = IProblem.IncompatibleExceptionInThrowsClause; + } + this.handle( + // Exception %1 is not compatible with throws clause in %2 + // 9.4.4 - The type of exception in the throws clause is incompatible. + id, + new String[] { + new String(exceptionType.sourceName()), + new String( + CharOperation.concat( + inheritedMethod.declaringClass.readableName(), + inheritedMethod.readableName(), + '.'))}, + new String[] { + new String(exceptionType.sourceName()), + new String( + CharOperation.concat( + inheritedMethod.declaringClass.shortReadableName(), + inheritedMethod.shortReadableName(), + '.'))}, + currentMethod.sourceStart(), + currentMethod.sourceEnd()); + } else + this.handle( + // Exception %1 in throws clause of %2 is not compatible with %3 + // 9.4.4 - The type of exception in the throws clause is incompatible. + IProblem.IncompatibleExceptionInInheritedMethodThrowsClause, + new String[] { + new String(exceptionType.sourceName()), + new String( + CharOperation.concat( + currentMethod.declaringClass.sourceName(), + currentMethod.readableName(), + '.')), + new String( + CharOperation.concat( + inheritedMethod.declaringClass.readableName(), + inheritedMethod.readableName(), + '.'))}, + new String[] { + new String(exceptionType.sourceName()), + new String( + CharOperation.concat( + currentMethod.declaringClass.sourceName(), + currentMethod.shortReadableName(), + '.')), + new String( + CharOperation.concat( + inheritedMethod.declaringClass.shortReadableName(), + inheritedMethod.shortReadableName(), + '.'))}, + type.sourceStart(), + type.sourceEnd()); +} +public void incompatibleReturnType(MethodBinding currentMethod, MethodBinding inheritedMethod) { + StringBuffer methodSignature = new StringBuffer(); + methodSignature + .append(inheritedMethod.declaringClass.readableName()) + .append('.') + .append(inheritedMethod.readableName()); + + StringBuffer shortSignature = new StringBuffer(); + shortSignature + .append(inheritedMethod.declaringClass.shortReadableName()) + .append('.') + .append(inheritedMethod.shortReadableName()); + + int id; + if (currentMethod.declaringClass.isInterface() + && !inheritedMethod.isPublic()){ // interface inheriting Object protected method + id = IProblem.IncompatibleReturnTypeForNonInheritedInterfaceMethod; + } else { + id = IProblem.IncompatibleReturnType; + } + this.handle( + id, + new String[] {methodSignature.toString()}, + new String[] {shortSignature.toString()}, + currentMethod.sourceStart(), + currentMethod.sourceEnd()); +} +public void incorrectLocationForEmptyDimension(ArrayAllocationExpression expression, int index) { + this.handle( + IProblem.IllegalDimension, + NoArgument, + NoArgument, + expression.dimensions[index + 1].sourceStart, + expression.dimensions[index + 1].sourceEnd); +} +public void indirectAccessToStaticField(ASTNode location, FieldBinding field){ + this.handle( + IProblem.IndirectAccessToStaticField, + new String[] {new String(field.declaringClass.readableName()), new String(field.name)}, + new String[] {new String(field.declaringClass.shortReadableName()), new String(field.name)}, + location.sourceStart, + fieldLocation(field, location)); +} +public void indirectAccessToStaticMethod(ASTNode location, MethodBinding method) { + this.handle( + IProblem.IndirectAccessToStaticMethod, + new String[] {new String(method.declaringClass.readableName()), new String(method.selector), parametersAsString(method)}, + new String[] {new String(method.declaringClass.shortReadableName()), new String(method.selector), parametersAsShortString(method)}, + location.sourceStart, + location.sourceEnd); +} +public void indirectAccessToStaticType(ASTNode location, ReferenceBinding type) { + this.handle( + IProblem.IndirectAccessToStaticMethod, + new String[] {new String(type.enclosingType().readableName()), new String(type.sourceName) }, + new String[] {new String(type.enclosingType().shortReadableName()), new String(type.sourceName) }, + location.sourceStart, + location.sourceEnd); +} +public void incorrectSwitchType(Expression expression, TypeBinding testType) { + this.handle( + IProblem.IncorrectSwitchType, + new String[] {new String(testType.readableName())}, + new String[] {new String(testType.shortReadableName())}, + expression.sourceStart, + expression.sourceEnd); +} +public void inheritedMethodReducesVisibility(SourceTypeBinding type, MethodBinding concreteMethod, MethodBinding[] abstractMethods) { + StringBuffer concreteSignature = new StringBuffer(); + concreteSignature + .append(concreteMethod.declaringClass.readableName()) + .append('.') + .append(concreteMethod.readableName()); + StringBuffer shortSignature = new StringBuffer(); + shortSignature + .append(concreteMethod.declaringClass.shortReadableName()) + .append('.') + .append(concreteMethod.shortReadableName()); + this.handle( + // The inherited method %1 cannot hide the public abstract method in %2 + IProblem.InheritedMethodReducesVisibility, + new String[] { + concreteSignature.toString(), + new String(abstractMethods[0].declaringClass.readableName())}, + new String[] { + new String(shortSignature.toString()), + new String(abstractMethods[0].declaringClass.shortReadableName())}, + type.sourceStart(), + type.sourceEnd()); +} +public void inheritedMethodsHaveIncompatibleReturnTypes(SourceTypeBinding type, MethodBinding[] inheritedMethods, int length) { + StringBuffer methodSignatures = new StringBuffer(); + StringBuffer shortSignatures = new StringBuffer(); + for (int i = length; --i >= 0;) { + methodSignatures + .append(inheritedMethods[i].declaringClass.readableName()) + .append('.') + .append(inheritedMethods[i].readableName()); + shortSignatures + .append(inheritedMethods[i].declaringClass.shortReadableName()) + .append('.') + .append(inheritedMethods[i].shortReadableName()); + if (i != 0){ + methodSignatures.append(", "); //$NON-NLS-1$ + shortSignatures.append(", "); //$NON-NLS-1$ + } + } + + this.handle( + // Return type is incompatible with %1 + // 9.4.2 - The return type from the method is incompatible with the declaration. + IProblem.IncompatibleReturnType, + new String[] {methodSignatures.toString()}, + new String[] {shortSignatures.toString()}, + type.sourceStart(), + type.sourceEnd()); +} +public void initializerMustCompleteNormally(FieldDeclaration fieldDecl) { + this.handle( + IProblem.InitializerMustCompleteNormally, + NoArgument, + NoArgument, + fieldDecl.sourceStart, + fieldDecl.sourceEnd); +} +public void innerTypesCannotDeclareStaticInitializers(ReferenceBinding innerType, ASTNode location) { + this.handle( + IProblem.CannotDefineStaticInitializerInLocalType, + new String[] {new String(innerType.readableName())}, + new String[] {new String(innerType.shortReadableName())}, + location.sourceStart, + location.sourceEnd); +} +public void interfaceCannotHaveConstructors(ConstructorDeclaration constructor) { + this.handle( + IProblem.InterfaceCannotHaveConstructors, + NoArgument, + NoArgument, + constructor.sourceStart, + constructor.sourceEnd, + constructor, + constructor.compilationResult()); +} +public void interfaceCannotHaveInitializers(SourceTypeBinding type, FieldDeclaration fieldDecl) { + String[] arguments = new String[] {new String(type.sourceName())}; + + this.handle( + IProblem.InterfaceCannotHaveInitializers, + arguments, + arguments, + fieldDecl.sourceStart, + fieldDecl.sourceEnd); +} +public void invalidBreak(ASTNode location) { + this.handle( + IProblem.InvalidBreak, + NoArgument, + NoArgument, + location.sourceStart, + location.sourceEnd); +} +public void invalidConstructor(Statement statement, MethodBinding targetConstructor) { + + boolean insideDefaultConstructor = + (this.referenceContext instanceof ConstructorDeclaration) + && ((ConstructorDeclaration)this.referenceContext).isDefaultConstructor(); + boolean insideImplicitConstructorCall = + (statement instanceof ExplicitConstructorCall) + && (((ExplicitConstructorCall) statement).accessMode == ExplicitConstructorCall.ImplicitSuper); + + int id = IProblem.UndefinedConstructor; //default... + switch (targetConstructor.problemId()) { + case NotFound : + if (insideDefaultConstructor){ + id = IProblem.UndefinedConstructorInDefaultConstructor; + } else if (insideImplicitConstructorCall){ + id = IProblem.UndefinedConstructorInImplicitConstructorCall; + } else { + id = IProblem.UndefinedConstructor; + } + break; + case NotVisible : + if (insideDefaultConstructor){ + id = IProblem.NotVisibleConstructorInDefaultConstructor; + } else if (insideImplicitConstructorCall){ + id = IProblem.NotVisibleConstructorInImplicitConstructorCall; + } else { + id = IProblem.NotVisibleConstructor; + } + break; + case Ambiguous : + if (insideDefaultConstructor){ + id = IProblem.AmbiguousConstructorInDefaultConstructor; + } else if (insideImplicitConstructorCall){ + id = IProblem.AmbiguousConstructorInImplicitConstructorCall; + } else { + id = IProblem.AmbiguousConstructor; + } + break; + case NoError : // 0 + default : + needImplementation(); // want to fail to see why we were here... + break; + } + + this.handle( + id, + new String[] {new String(targetConstructor.declaringClass.readableName()), parametersAsString(targetConstructor)}, + new String[] {new String(targetConstructor.declaringClass.shortReadableName()), parametersAsShortString(targetConstructor)}, + statement.sourceStart, + statement.sourceEnd); +} + +public void invalidExplicitConstructorCall(ASTNode location) { + + this.handle( + IProblem.InvalidExplicitConstructorCall, + NoArgument, + NoArgument, + location.sourceStart, + location.sourceEnd); +} +public void invalidContinue(ASTNode location) { + this.handle( + IProblem.InvalidContinue, + NoArgument, + NoArgument, + location.sourceStart, + location.sourceEnd); +} +public void invalidEnclosingType(Expression expression, TypeBinding type, ReferenceBinding enclosingType) { + + if (enclosingType.isAnonymousType()) enclosingType = enclosingType.superclass(); + int flag = IProblem.UndefinedType; // default + switch (type.problemId()) { + case NotFound : // 1 + flag = IProblem.UndefinedType; + break; + case NotVisible : // 2 + flag = IProblem.NotVisibleType; + break; + case Ambiguous : // 3 + flag = IProblem.AmbiguousType; + break; + case InternalNameProvided : + flag = IProblem.InternalTypeNameProvided; + break; + case NoError : // 0 + default : + needImplementation(); // want to fail to see why we were here... + break; + } + + this.handle( + flag, + new String[] {new String(enclosingType.readableName()) + "." + new String(type.readableName())}, //$NON-NLS-1$ + new String[] {new String(enclosingType.shortReadableName()) + "." + new String(type.shortReadableName())}, //$NON-NLS-1$ + expression.sourceStart, + expression.sourceEnd); +} +public void invalidExpressionAsStatement(Expression expression){ + this.handle( + IProblem.InvalidExpressionAsStatement, + NoArgument, + NoArgument, + expression.sourceStart, + expression.sourceEnd); +} +public void invalidField(FieldReference fieldRef, TypeBinding searchedType) { + int id = IProblem.UndefinedField; + FieldBinding field = fieldRef.binding; + switch (field.problemId()) { + case NotFound : + id = IProblem.UndefinedField; +/* also need to check that the searchedType is the receiver type + if (searchedType.isHierarchyInconsistent()) + severity = SecondaryError; +*/ + break; + case NotVisible : + id = IProblem.NotVisibleField; + break; + case Ambiguous : + id = IProblem.AmbiguousField; + break; + case NonStaticReferenceInStaticContext : + id = IProblem.NonStaticFieldFromStaticInvocation; + break; + case NonStaticReferenceInConstructorInvocation : + id = IProblem.InstanceFieldDuringConstructorInvocation; + break; + case InheritedNameHidesEnclosingName : + id = IProblem.InheritedFieldHidesEnclosingName; + break; + case ReceiverTypeNotVisible : + this.handle( + IProblem.NotVisibleType, // cannot occur in javadoc comments + new String[] {new String(searchedType.leafComponentType().readableName())}, + new String[] {new String(searchedType.leafComponentType().shortReadableName())}, + fieldRef.receiver.sourceStart, + fieldRef.receiver.sourceEnd); + return; + + case NoError : // 0 + default : + needImplementation(); // want to fail to see why we were here... + break; + } + + String[] arguments = new String[] {new String(field.readableName())}; + this.handle( + id, + arguments, + arguments, + fieldRef.sourceStart, + fieldRef.sourceEnd); +} +public void invalidField(NameReference nameRef, FieldBinding field) { + int id = IProblem.UndefinedField; + switch (field.problemId()) { + case NotFound : + id = IProblem.UndefinedField; + break; + case NotVisible : + id = IProblem.NotVisibleField; + break; + case Ambiguous : + id = IProblem.AmbiguousField; + break; + case NonStaticReferenceInStaticContext : + id = IProblem.NonStaticFieldFromStaticInvocation; + break; + case NonStaticReferenceInConstructorInvocation : + id = IProblem.InstanceFieldDuringConstructorInvocation; + break; + case InheritedNameHidesEnclosingName : + id = IProblem.InheritedFieldHidesEnclosingName; + break; + case ReceiverTypeNotVisible : + this.handle( + IProblem.NotVisibleType, + new String[] {new String(field.declaringClass.leafComponentType().readableName())}, + new String[] {new String(field.declaringClass.leafComponentType().shortReadableName())}, + nameRef.sourceStart, + nameRef.sourceEnd); + return; + case NoError : // 0 + default : + needImplementation(); // want to fail to see why we were here... + break; + } + String[] arguments = new String[] {new String(field.readableName())}; + this.handle( + id, + arguments, + arguments, + nameRef.sourceStart, + nameRef.sourceEnd); +} +public void invalidField(QualifiedNameReference nameRef, FieldBinding field, int index, TypeBinding searchedType) { + //the resolution of the index-th field of qname failed + //qname.otherBindings[index] is the binding that has produced the error + + //The different targetted errors should be : + //UndefinedField + //NotVisibleField + //AmbiguousField + + if (searchedType.isBaseType()) { + this.handle( + IProblem.NoFieldOnBaseType, + new String[] { + new String(searchedType.readableName()), + CharOperation.toString(CharOperation.subarray(nameRef.tokens, 0, index)), + new String(nameRef.tokens[index])}, + new String[] { + new String(searchedType.sourceName()), + CharOperation.toString(CharOperation.subarray(nameRef.tokens, 0, index)), + new String(nameRef.tokens[index])}, + nameRef.sourceStart, + (int) nameRef.sourcePositions[index]); + return; + } + + int id = IProblem.UndefinedField; + switch (field.problemId()) { + case NotFound : + id = IProblem.UndefinedField; +/* also need to check that the searchedType is the receiver type + if (searchedType.isHierarchyInconsistent()) + severity = SecondaryError; +*/ + break; + case NotVisible : + id = IProblem.NotVisibleField; + break; + case Ambiguous : + id = IProblem.AmbiguousField; + break; + case NonStaticReferenceInStaticContext : + id = IProblem.NonStaticFieldFromStaticInvocation; + break; + case NonStaticReferenceInConstructorInvocation : + id = IProblem.InstanceFieldDuringConstructorInvocation; + break; + case InheritedNameHidesEnclosingName : + id = IProblem.InheritedFieldHidesEnclosingName; + break; + case ReceiverTypeNotVisible : + this.handle( + IProblem.NotVisibleType, + new String[] {new String(searchedType.leafComponentType().readableName())}, + new String[] {new String(searchedType.leafComponentType().shortReadableName())}, + nameRef.sourceStart, + nameRef.sourceEnd); + return; + case NoError : // 0 + default : + needImplementation(); // want to fail to see why we were here... + break; + } + String[] arguments = new String[] {CharOperation.toString(CharOperation.subarray(nameRef.tokens, 0, index + 1))}; + this.handle( + id, + arguments, + arguments, + nameRef.sourceStart, + (int) nameRef.sourcePositions[index]); +} +public void invalidMethod(MessageSend messageSend, MethodBinding method) { + // CODE should be UPDATED according to error coding in the different method binding errors + // The different targetted errors should be : + // UndefinedMethod + // NotVisibleMethod + // AmbiguousMethod + // InheritedNameHidesEnclosingName + // InstanceMethodDuringConstructorInvocation + // StaticMethodRequested + + int id = IProblem.UndefinedMethod; //default... + switch (method.problemId()) { + case NotFound : + id = IProblem.UndefinedMethod; + break; + case NotVisible : + id = IProblem.NotVisibleMethod; + break; + case Ambiguous : + id = IProblem.AmbiguousMethod; + break; + case InheritedNameHidesEnclosingName : + id = IProblem.InheritedMethodHidesEnclosingName; + break; + case NonStaticReferenceInConstructorInvocation : + id = IProblem.InstanceMethodDuringConstructorInvocation; + break; + case NonStaticReferenceInStaticContext : + id = IProblem.StaticMethodRequested; + break; + case ReceiverTypeNotVisible : + this.handle( + IProblem.NotVisibleType, // cannot occur in javadoc comments + new String[] {new String(method.declaringClass.leafComponentType().readableName())}, + new String[] {new String(method.declaringClass.leafComponentType().shortReadableName())}, + messageSend.receiver.sourceStart, + messageSend.receiver.sourceEnd); + return; + + case NoError : // 0 + default : + needImplementation(); // want to fail to see why we were here... + break; + } + + if (id == IProblem.UndefinedMethod) { + ProblemMethodBinding problemMethod = (ProblemMethodBinding) method; + if (problemMethod.closestMatch != null) { + String closestParameterTypeNames = parametersAsString(problemMethod.closestMatch); + String parameterTypeNames = parametersAsString(method); + String closestParameterTypeShortNames = parametersAsShortString(problemMethod.closestMatch); + String parameterTypeShortNames = parametersAsShortString(method); + if (closestParameterTypeShortNames.equals(parameterTypeShortNames)){ + closestParameterTypeShortNames = closestParameterTypeNames; + parameterTypeShortNames = parameterTypeNames; + } + id = IProblem.ParameterMismatch; + this.handle( + id, + new String[] { + new String(problemMethod.closestMatch.declaringClass.readableName()), + new String(problemMethod.closestMatch.selector), + closestParameterTypeNames, + parameterTypeNames + }, + new String[] { + new String(problemMethod.closestMatch.declaringClass.shortReadableName()), + new String(problemMethod.closestMatch.selector), + closestParameterTypeShortNames, + parameterTypeShortNames + }, + (int) (messageSend.nameSourcePosition >>> 32), + (int) messageSend.nameSourcePosition); + return; + } + } + + this.handle( + id, + new String[] { + new String(method.declaringClass.readableName()), + new String(method.selector), parametersAsString(method)}, + new String[] { + new String(method.declaringClass.shortReadableName()), + new String(method.selector), parametersAsShortString(method)}, + (int) (messageSend.nameSourcePosition >>> 32), + (int) messageSend.nameSourcePosition); +} +public void invalidNullToSynchronize(Expression expression) { + this.handle( + IProblem.InvalidNullToSynchronized, + NoArgument, + NoArgument, + expression.sourceStart, + expression.sourceEnd); +} +public void invalidOperator(BinaryExpression expression, TypeBinding leftType, TypeBinding rightType) { + String leftName = new String(leftType.readableName()); + String rightName = new String(rightType.readableName()); + String leftShortName = new String(leftType.shortReadableName()); + String rightShortName = new String(rightType.shortReadableName()); + if (leftShortName.equals(rightShortName)){ + leftShortName = leftName; + rightShortName = rightName; + } + this.handle( + IProblem.InvalidOperator, + new String[] { + expression.operatorToString(), + leftName + ", " + rightName}, //$NON-NLS-1$ + new String[] { + expression.operatorToString(), + leftShortName + ", " + rightShortName}, //$NON-NLS-1$ + expression.sourceStart, + expression.sourceEnd); +} +public void invalidOperator(CompoundAssignment assign, TypeBinding leftType, TypeBinding rightType) { + String leftName = new String(leftType.readableName()); + String rightName = new String(rightType.readableName()); + String leftShortName = new String(leftType.shortReadableName()); + String rightShortName = new String(rightType.shortReadableName()); + if (leftShortName.equals(rightShortName)){ + leftShortName = leftName; + rightShortName = rightName; + } + this.handle( + IProblem.InvalidOperator, + new String[] { + assign.operatorToString(), + leftName + ", " + rightName}, //$NON-NLS-1$ + new String[] { + assign.operatorToString(), + leftShortName + ", " + rightShortName}, //$NON-NLS-1$ + assign.sourceStart, + assign.sourceEnd); +} +public void invalidOperator(UnaryExpression expression, TypeBinding type) { + this.handle( + IProblem.InvalidOperator, + new String[] {expression.operatorToString(), new String(type.readableName())}, + new String[] {expression.operatorToString(), new String(type.shortReadableName())}, + expression.sourceStart, + expression.sourceEnd); +} +public void invalidParenthesizedExpression(ASTNode reference) { + this.handle( + IProblem.InvalidParenthesizedExpression, + NoArgument, + NoArgument, + reference.sourceStart, + reference.sourceEnd); +} +public void invalidSuperclass(SourceTypeBinding type, TypeReference superclassRef, ReferenceBinding expectedType) { + int problemId = expectedType.problemId(); + int id; + switch (problemId) { + case NotFound : // 1 + id = IProblem.SuperclassNotFound; + break; + case NotVisible : // 2 + id = IProblem.SuperclassNotVisible; + break; + case Ambiguous : // 3 + id = IProblem.SuperclassAmbiguous; + break; + case InternalNameProvided : // 4 + id = IProblem.SuperclassInternalNameProvided; + break; + case InheritedNameHidesEnclosingName : // 5 + id = IProblem.SuperclassInheritedNameHidesEnclosingName; + break; + case NoError : // 0 + default : + needImplementation(); // want to fail to see why we were here... + return; + } + this.handle( + id, + new String[] {new String(expectedType.readableName()), new String(type.sourceName())}, + new String[] {new String(expectedType.shortReadableName()), new String(type.sourceName())}, + superclassRef.sourceStart, + superclassRef.sourceEnd); +} +public void invalidSuperinterface(SourceTypeBinding type, TypeReference superinterfaceRef, ReferenceBinding expectedType) { + int problemId = expectedType.problemId(); + int id; + switch (problemId) { + case NotFound : // 1 + id = IProblem.InterfaceNotFound; + break; + case NotVisible : // 2 + id = IProblem.InterfaceNotVisible; + break; + case Ambiguous : // 3 + id = IProblem.InterfaceAmbiguous; + break; + case InternalNameProvided : // 4 + id = IProblem.InterfaceInternalNameProvided; + break; + case InheritedNameHidesEnclosingName : // 5 + id = IProblem.InterfaceInheritedNameHidesEnclosingName; + break; + case NoError : // 0 + default : + needImplementation(); // want to fail to see why we were here... + return; + } + this.handle( + id, + new String[] {new String(expectedType.readableName()), new String(type.sourceName())}, + new String[] {new String(expectedType.shortReadableName()), new String(type.sourceName())}, + superinterfaceRef.sourceStart, + superinterfaceRef.sourceEnd); +} +public void invalidType(ASTNode location, TypeBinding type) { + int id = IProblem.UndefinedType; // default + switch (type.problemId()) { + case NotFound : + id = IProblem.UndefinedType; + break; + case NotVisible : + id = IProblem.NotVisibleType; + break; + case Ambiguous : + id = IProblem.AmbiguousType; + break; + case InternalNameProvided : + id = IProblem.InternalTypeNameProvided; + break; + case InheritedNameHidesEnclosingName : + id = IProblem.InheritedTypeHidesEnclosingName; + break; + case NoError : // 0 + default : + needImplementation(); // want to fail to see why we were here... + break; + } + + int end = location.sourceEnd; + if (location instanceof QualifiedNameReference) { + QualifiedNameReference ref = (QualifiedNameReference) location; + if (ref.indexOfFirstFieldBinding >= 1) + end = (int) ref.sourcePositions[ref.indexOfFirstFieldBinding - 1]; + } + this.handle( + id, + new String[] {new String(type.readableName())}, + new String[] {new String(type.shortReadableName())}, + location.sourceStart, + end); +} +public void invalidTypeReference(Expression expression) { + this.handle( + IProblem.InvalidTypeExpression, + NoArgument, + NoArgument, + expression.sourceStart, + expression.sourceEnd); +} +public void invalidTypeToSynchronize(Expression expression, TypeBinding type) { + this.handle( + IProblem.InvalidTypeToSynchronized, + new String[] {new String(type.readableName())}, + new String[] {new String(type.shortReadableName())}, + expression.sourceStart, + expression.sourceEnd); +} +public void invalidUnaryExpression(Expression expression) { + this.handle( + IProblem.InvalidUnaryExpression, + NoArgument, + NoArgument, + expression.sourceStart, + expression.sourceEnd); +} +public void isClassPathCorrect(char[][] wellKnownTypeName, CompilationUnitDeclaration compUnitDecl) { + this.referenceContext = compUnitDecl; + String[] arguments = new String[] {CharOperation.toString(wellKnownTypeName)}; + this.handle( + IProblem.IsClassPathCorrect, + arguments, + arguments, + AbortCompilation | Error, + 0, + 0); +} +public void javadocDuplicatedReturnTag(int sourceStart, int sourceEnd){ + this.handle(IProblem.JavadocDuplicateReturnTag, NoArgument, NoArgument, sourceStart, sourceEnd); +} +public void javadocDeprecatedField(FieldBinding field, ASTNode location, int modifiers) { + if (javadocVisibility(this.options.reportInvalidJavadocTagsVisibility, modifiers)) { + this.handle( + IProblem.JavadocUsingDeprecatedField, + new String[] {new String(field.declaringClass.readableName()), new String(field.name)}, + new String[] {new String(field.declaringClass.shortReadableName()), new String(field.name)}, + location.sourceStart, + location.sourceEnd); + } +} +public void javadocDeprecatedMethod(MethodBinding method, ASTNode location, int modifiers) { + if (javadocVisibility(this.options.reportInvalidJavadocTagsVisibility, modifiers)) { + if (method.isConstructor()) { + this.handle( + IProblem.JavadocUsingDeprecatedConstructor, + new String[] {new String(method.declaringClass.readableName()), parametersAsString(method)}, + new String[] {new String(method.declaringClass.shortReadableName()), parametersAsShortString(method)}, + location.sourceStart, + location.sourceEnd); + } else { + this.handle( + IProblem.JavadocUsingDeprecatedMethod, + new String[] {new String(method.declaringClass.readableName()), new String(method.selector), parametersAsString(method)}, + new String[] {new String(method.declaringClass.shortReadableName()), new String(method.selector), parametersAsShortString(method)}, + location.sourceStart, + location.sourceEnd); + } + } +} +public void javadocDeprecatedType(TypeBinding type, ASTNode location, int modifiers) { + if (location == null) return; // 1G828DN - no type ref for synthetic arguments + if (javadocVisibility(this.options.reportInvalidJavadocTagsVisibility, modifiers)) { + this.handle( + IProblem.JavadocUsingDeprecatedType, + new String[] {new String(type.readableName())}, + new String[] {new String(type.shortReadableName())}, + location.sourceStart, + location.sourceEnd); + } +} +public void javadocDuplicatedParamTag(JavadocSingleNameReference param, int modifiers) { + if (javadocVisibility(this.options.reportInvalidJavadocTagsVisibility, modifiers)) { + String[] arguments = new String[] {String.valueOf(param.token)}; + this.handle(IProblem.JavadocDuplicateParamName, arguments, arguments, param.sourceStart, param.sourceEnd); + } +} +public void javadocDuplicatedThrowsClassName(TypeReference typeReference, int modifiers) { + if (javadocVisibility(this.options.reportInvalidJavadocTagsVisibility, modifiers)) { + String[] arguments = new String[] {String.valueOf(typeReference.resolvedType.sourceName())}; + this.handle(IProblem.JavadocDuplicateThrowsClassName, arguments, arguments, typeReference.sourceStart, typeReference.sourceEnd); + } +} +public void javadocErrorNoMethodFor(MessageSend messageSend, TypeBinding recType, TypeBinding[] params, int modifiers) { + StringBuffer buffer = new StringBuffer(); + StringBuffer shortBuffer = new StringBuffer(); + for (int i = 0, length = params.length; i < length; i++) { + if (i != 0){ + buffer.append(", "); //$NON-NLS-1$ + shortBuffer.append(", "); //$NON-NLS-1$ + } + buffer.append(new String(params[i].readableName())); + shortBuffer.append(new String(params[i].shortReadableName())); + } + + int id = recType.isArrayType() ? IProblem.JavadocNoMessageSendOnArrayType : IProblem.JavadocNoMessageSendOnBaseType; + if (javadocVisibility(this.options.reportInvalidJavadocTagsVisibility, modifiers)) { + this.handle( + id, + new String[] {new String(recType.readableName()), new String(messageSend.selector), buffer.toString()}, + new String[] {new String(recType.shortReadableName()), new String(messageSend.selector), shortBuffer.toString()}, + messageSend.sourceStart, + messageSend.sourceEnd); + } +} +public void javadocInvalidConstructor(Statement statement, MethodBinding targetConstructor, int modifiers) { + + if (!javadocVisibility(this.options.reportInvalidJavadocTagsVisibility, modifiers)) { + return; + } +// boolean insideDefaultConstructor = +// (this.referenceContext instanceof ConstructorDeclaration) +// && ((ConstructorDeclaration)this.referenceContext).isDefaultConstructor(); +// boolean insideImplicitConstructorCall = +// (statement instanceof ExplicitConstructorCall) +// && (((ExplicitConstructorCall) statement).accessMode == ExplicitConstructorCall.ImplicitSuper); + + int id = IProblem.JavadocUndefinedConstructor; //default... + switch (targetConstructor.problemId()) { + case NotFound : +// if (insideDefaultConstructor){ +// id = IProblem.JavadocUndefinedConstructorInDefaultConstructor; +// } else if (insideImplicitConstructorCall){ +// id = IProblem.JavadocUndefinedConstructorInImplicitConstructorCall; +// } else { + id = IProblem.JavadocUndefinedConstructor; +// } + break; + case NotVisible : +// if (insideDefaultConstructor){ +// id = IProblem.JavadocNotVisibleConstructorInDefaultConstructor; +// } else if (insideImplicitConstructorCall){ +// id = IProblem.JavadocNotVisibleConstructorInImplicitConstructorCall; +// } else { + id = IProblem.JavadocNotVisibleConstructor; +// } + break; + case Ambiguous : +// if (insideDefaultConstructor){ +// id = IProblem.AmbiguousConstructorInDefaultConstructor; +// } else if (insideImplicitConstructorCall){ +// id = IProblem.AmbiguousConstructorInImplicitConstructorCall; +// } else { + id = IProblem.JavadocAmbiguousConstructor; +// } + break; + case NoError : // 0 + default : + needImplementation(); // want to fail to see why we were here... + break; + } + + this.handle( + id, + new String[] {new String(targetConstructor.declaringClass.readableName()), parametersAsString(targetConstructor)}, + new String[] {new String(targetConstructor.declaringClass.shortReadableName()), parametersAsShortString(targetConstructor)}, + statement.sourceStart, + statement.sourceEnd); +} +public void javadocAmbiguousMethodReference(int sourceStart, int sourceEnd, Binding fieldBinding, int modifiers) { + int id = IProblem.JavadocAmbiguousMethodReference; + if (javadocVisibility(this.options.reportInvalidJavadocTagsVisibility, modifiers)) { + String[] arguments = new String[] {new String(fieldBinding.readableName())}; + handle(id, arguments, arguments, sourceStart, sourceEnd); + } +} +/* + * Similar implementation than invalidField(FieldReference...) + * Note that following problem id cannot occur for Javadoc: + * - NonStaticReferenceInStaticContext : + * - NonStaticReferenceInConstructorInvocation : + * - ReceiverTypeNotVisible : + */ +public void javadocInvalidField(int sourceStart, int sourceEnd, Binding fieldBinding, TypeBinding searchedType, int modifiers) { + int id = IProblem.JavadocUndefinedField; + switch (fieldBinding.problemId()) { + case NotFound : + id = IProblem.JavadocUndefinedField; + break; + case NotVisible : + id = IProblem.JavadocNotVisibleField; + break; + case Ambiguous : + id = IProblem.JavadocAmbiguousField; + break; + case InheritedNameHidesEnclosingName : + id = IProblem.JavadocInheritedFieldHidesEnclosingName; + break; + case NoError : // 0 + default : + needImplementation(); // want to fail to see why we were here... + break; + } + + if (javadocVisibility(this.options.reportInvalidJavadocTagsVisibility, modifiers)) { + String[] arguments = new String[] {new String(fieldBinding.readableName())}; + handle(id, arguments, arguments, sourceStart, sourceEnd); + } +} +/* + * Similar implementation than invalidMethod(MessageSend...) + * Note that following problem id cannot occur for Javadoc: + * - NonStaticReferenceInStaticContext : + * - NonStaticReferenceInConstructorInvocation : + * - ReceiverTypeNotVisible : + */ +public void javadocInvalidMethod(MessageSend messageSend, MethodBinding method, int modifiers) { + if (!javadocVisibility(this.options.reportInvalidJavadocTagsVisibility, modifiers)) { + return; + } + int id = IProblem.JavadocUndefinedMethod; //default... + switch (method.problemId()) { + case NotFound : + id = IProblem.JavadocUndefinedMethod; + break; + case NotVisible : + id = IProblem.JavadocNotVisibleMethod; + break; + case Ambiguous : + id = IProblem.JavadocAmbiguousMethod; + break; + case InheritedNameHidesEnclosingName : + id = IProblem.JavadocInheritedMethodHidesEnclosingName; + break; + case NoError : // 0 + default : + needImplementation(); // want to fail to see why we were here... + break; + } + + if (id == IProblem.JavadocUndefinedMethod) { + ProblemMethodBinding problemMethod = (ProblemMethodBinding) method; + if (problemMethod.closestMatch != null) { + String closestParameterTypeNames = parametersAsString(problemMethod.closestMatch); + String parameterTypeNames = parametersAsString(method); + String closestParameterTypeShortNames = parametersAsShortString(problemMethod.closestMatch); + String parameterTypeShortNames = parametersAsShortString(method); + if (closestParameterTypeShortNames.equals(parameterTypeShortNames)){ + closestParameterTypeShortNames = closestParameterTypeNames; + parameterTypeShortNames = parameterTypeNames; + } + this.handle( + IProblem.JavadocParameterMismatch, + new String[] { + new String(problemMethod.closestMatch.declaringClass.readableName()), + new String(problemMethod.closestMatch.selector), + closestParameterTypeNames, + parameterTypeNames + }, + new String[] { + new String(problemMethod.closestMatch.declaringClass.shortReadableName()), + new String(problemMethod.closestMatch.selector), + closestParameterTypeShortNames, + parameterTypeShortNames + }, + (int) (messageSend.nameSourcePosition >>> 32), + (int) messageSend.nameSourcePosition); + return; + } + } + + this.handle( + id, + new String[] { + new String(method.declaringClass.readableName()), + new String(method.selector), parametersAsString(method)}, + new String[] { + new String(method.declaringClass.shortReadableName()), + new String(method.selector), parametersAsShortString(method)}, + (int) (messageSend.nameSourcePosition >>> 32), + (int) messageSend.nameSourcePosition); +} +public void javadocInvalidParamName(JavadocSingleNameReference param, int modifiers) { + if (javadocVisibility(this.options.reportInvalidJavadocTagsVisibility, modifiers)) { + String[] arguments = new String[] {String.valueOf(param.token)}; + this.handle(IProblem.JavadocInvalidParamName, arguments, arguments, param.sourceStart, param.sourceEnd); + } +} +public void javadocInvalidSeeReference(int sourceStart, int sourceEnd) { + this.handle(IProblem.JavadocInvalidSeeReference, NoArgument, NoArgument, sourceStart, sourceEnd); +} +public void javadocInvalidSeeReferenceArgs(int sourceStart, int sourceEnd) { + this.handle(IProblem.JavadocInvalidSeeArgs, NoArgument, NoArgument, sourceStart, sourceEnd); +} +public void javadocInvalidSeeUrlReference(int sourceStart, int sourceEnd) { + this.handle(IProblem.JavadocInvalidSeeHref, NoArgument, NoArgument, sourceStart, sourceEnd); +} +public void javadocInvalidTag(int sourceStart, int sourceEnd) { + this.handle(IProblem.JavadocInvalidTag, NoArgument, NoArgument, sourceStart, sourceEnd); +} +public void javadocInvalidThrowsClass(int sourceStart, int sourceEnd) { + this.handle(IProblem.JavadocInvalidThrowsClass, NoArgument, NoArgument, sourceStart, sourceEnd); +} +public void javadocInvalidThrowsClassName(TypeReference typeReference, int modifiers) { + if (javadocVisibility(this.options.reportInvalidJavadocTagsVisibility, modifiers)) { + String[] arguments = new String[] {String.valueOf(typeReference.resolvedType.sourceName())}; + this.handle(IProblem.JavadocInvalidThrowsClassName, arguments, arguments, typeReference.sourceStart, typeReference.sourceEnd); + } +} +public void javadocInvalidType(ASTNode location, TypeBinding type, int modifiers) { + if (javadocVisibility(this.options.reportInvalidJavadocTagsVisibility, modifiers)) { + int id = IProblem.JavadocUndefinedType; // default + switch (type.problemId()) { + case NotFound : + id = IProblem.JavadocUndefinedType; + break; + case NotVisible : + id = IProblem.JavadocNotVisibleType; + break; + case Ambiguous : + id = IProblem.JavadocAmbiguousType; + break; + case InternalNameProvided : + id = IProblem.JavadocInternalTypeNameProvided; + break; + case InheritedNameHidesEnclosingName : + id = IProblem.JavadocInheritedNameHidesEnclosingTypeName; + break; + case NoError : // 0 + default : + needImplementation(); // want to fail to see why we were here... + break; + } + this.handle( + id, + new String[] {new String(type.readableName())}, + new String[] {new String(type.shortReadableName())}, + location.sourceStart, + location.sourceEnd); + } +} +public void javadocMalformedSeeReference(int sourceStart, int sourceEnd) { + this.handle(IProblem.JavadocMalformedSeeReference, NoArgument, NoArgument, sourceStart, sourceEnd); +} +public void javadocMissing(int sourceStart, int sourceEnd, int modifiers){ + boolean overriding = (modifiers & (CompilerModifiers.AccImplementing+CompilerModifiers.AccOverriding)) != 0; + boolean report = (this.options.getSeverity(CompilerOptions.MissingJavadocComments) != ProblemSeverities.Ignore) + && (!overriding || this.options.reportMissingJavadocCommentsOverriding); + if (report) { + String arg = javadocVisibilityArgument(this.options.reportMissingJavadocCommentsVisibility, modifiers); + if (arg != null) { + String[] arguments = new String[] { arg }; + this.handle(IProblem.JavadocMissing, arguments, arguments, sourceStart, sourceEnd); + } + } +} +public void javadocMissingParamName(int sourceStart, int sourceEnd){ + this.handle(IProblem.JavadocMissingParamName, NoArgument, NoArgument, sourceStart, sourceEnd); +} +public void javadocMissingParamTag(Argument param, int modifiers) { + boolean overriding = (modifiers & (CompilerModifiers.AccImplementing+CompilerModifiers.AccOverriding)) != 0; + boolean report = (this.options.getSeverity(CompilerOptions.MissingJavadocTags) != ProblemSeverities.Ignore) + && (!overriding || this.options.reportMissingJavadocTagsOverriding); + if (report && javadocVisibility(this.options.reportMissingJavadocTagsVisibility, modifiers)) { + String[] arguments = new String[] { String.valueOf(param.name) }; + this.handle(IProblem.JavadocMissingParamTag, arguments, arguments, param.sourceStart, param.sourceEnd); + } +} +public void javadocMissingReturnTag(int sourceStart, int sourceEnd, int modifiers){ + boolean overriding = (modifiers & (CompilerModifiers.AccImplementing+CompilerModifiers.AccOverriding)) != 0; + boolean report = (this.options.getSeverity(CompilerOptions.MissingJavadocTags) != ProblemSeverities.Ignore) + && (!overriding || this.options.reportMissingJavadocTagsOverriding); + if (report && javadocVisibility(this.options.reportMissingJavadocTagsVisibility, modifiers)) { + this.handle(IProblem.JavadocMissingReturnTag, NoArgument, NoArgument, sourceStart, sourceEnd); + } +} +public void javadocMissingSeeReference(int sourceStart, int sourceEnd){ + this.handle(IProblem.JavadocMissingSeeReference, NoArgument, NoArgument, sourceStart, sourceEnd); +} +public void javadocMissingThrowsClassName(int sourceStart, int sourceEnd){ + this.handle(IProblem.JavadocMissingThrowsClassName, NoArgument, NoArgument, sourceStart, sourceEnd); +} +public void javadocMissingThrowsTag(TypeReference typeRef, int modifiers){ + boolean overriding = (modifiers & (CompilerModifiers.AccImplementing+CompilerModifiers.AccOverriding)) != 0; + boolean report = (this.options.getSeverity(CompilerOptions.MissingJavadocTags) != ProblemSeverities.Ignore) + && (!overriding || this.options.reportMissingJavadocTagsOverriding); + if (report && javadocVisibility(this.options.reportMissingJavadocTagsVisibility, modifiers)) { + String[] arguments = new String[] { String.valueOf(typeRef.resolvedType.sourceName()) }; + this.handle(IProblem.JavadocMissingThrowsTag, arguments, arguments, typeRef.sourceStart, typeRef.sourceEnd); + } +} +public void javadocUnexpectedTag(int sourceStart, int sourceEnd) { + this.handle(IProblem.JavadocUnexpectedTag, NoArgument, NoArgument, sourceStart, sourceEnd); +} +public void javadocUnterminatedInlineTag(int sourceStart, int sourceEnd) { + this.handle(IProblem.JavadocUnterminatedInlineTag, NoArgument, NoArgument, sourceStart, sourceEnd); +} +private boolean javadocVisibility(int visibility, int modifiers) { + switch (modifiers & CompilerModifiers.AccVisibilityMASK) { + case IConstants.AccPublic : + return true; + case IConstants.AccProtected: + return (visibility != IConstants.AccPublic); + case IConstants.AccDefault: + return (visibility == IConstants.AccDefault || visibility == IConstants.AccPrivate); + case IConstants.AccPrivate: + return (visibility == IConstants.AccPrivate); + } + return true; +} +private String javadocVisibilityArgument(int visibility, int modifiers) { + String argument = null; + switch (modifiers & CompilerModifiers.AccVisibilityMASK) { + case IConstants.AccPublic : + argument = CompilerOptions.PUBLIC; + break; + case IConstants.AccProtected: + if (visibility != IConstants.AccPublic) { + argument = CompilerOptions.PROTECTED; + } + break; + case IConstants.AccDefault: + if (visibility == IConstants.AccDefault || visibility == IConstants.AccPrivate) { + argument = CompilerOptions.DEFAULT; + } + break; + case IConstants.AccPrivate: + if (visibility == IConstants.AccPrivate) { + argument = CompilerOptions.PRIVATE; + } + break; + } + return argument; +} +public void localVariableHiding(LocalDeclaration local, Binding hiddenVariable, boolean isSpecialArgHidingField) { + if (hiddenVariable instanceof LocalVariableBinding) { + String[] arguments = new String[] {new String(local.name) }; + this.handle( + (local instanceof Argument) + ? IProblem.ArgumentHidingLocalVariable + : IProblem.LocalVariableHidingLocalVariable, + arguments, + arguments, + local.sourceStart, + local.sourceEnd); + } else if (hiddenVariable instanceof FieldBinding) { + if (isSpecialArgHidingField && !this.options.reportSpecialParameterHidingField){ + return; + } + FieldBinding field = (FieldBinding) hiddenVariable; + this.handle( + (local instanceof Argument) + ? IProblem.ArgumentHidingField + : IProblem.LocalVariableHidingField, + new String[] {new String(local.name) , new String(field.declaringClass.readableName()) }, + new String[] {new String(local.name), new String(field.declaringClass.shortReadableName()) }, + local.sourceStart, + local.sourceEnd); + } +} +public void methodNeedBody(AbstractMethodDeclaration methodDecl) { + this.handle( + IProblem.MethodRequiresBody, + NoArgument, + NoArgument, + methodDecl.sourceStart, + methodDecl.sourceEnd); +} +public void methodNeedingNoBody(MethodDeclaration methodDecl) { + this.handle( + ((methodDecl.modifiers & IConstants.AccNative) != 0) ? IProblem.BodyForNativeMethod : IProblem.BodyForAbstractMethod, + NoArgument, + NoArgument, + methodDecl.sourceStart, + methodDecl.sourceEnd); +} +public void methodWithConstructorName(MethodDeclaration methodDecl) { + this.handle( + IProblem.MethodButWithConstructorName, + NoArgument, + NoArgument, + methodDecl.sourceStart, + methodDecl.sourceEnd); +} +public void missingReturnType(AbstractMethodDeclaration methodDecl) { + this.handle( + IProblem.MissingReturnType, + NoArgument, + NoArgument, + methodDecl.sourceStart, + methodDecl.sourceEnd); +} +public void missingSemiColon(Expression expression){ + this.handle( + IProblem.MissingSemiColon, + NoArgument, + NoArgument, + expression.sourceStart, + expression.sourceEnd); +} +public void mustDefineDimensionsOrInitializer(ArrayAllocationExpression expression) { + this.handle( + IProblem.MustDefineEitherDimensionExpressionsOrInitializer, + NoArgument, + NoArgument, + expression.sourceStart, + expression.sourceEnd); +} +public void mustSpecifyPackage(CompilationUnitDeclaration compUnitDecl) { + String[] arguments = new String[] {new String(compUnitDecl.getFileName())}; + this.handle( + IProblem.MustSpecifyPackage, + arguments, + arguments, + compUnitDecl.sourceStart, + compUnitDecl.sourceStart + 1); +} +public void mustUseAStaticMethod(MessageSend messageSend, MethodBinding method) { + this.handle( + IProblem.StaticMethodRequested, + new String[] {new String(method.declaringClass.readableName()), new String(method.selector), parametersAsString(method)}, + new String[] {new String(method.declaringClass.shortReadableName()), new String(method.selector), parametersAsShortString(method)}, + messageSend.sourceStart, + messageSend.sourceEnd); +} + +public void nativeMethodsCannotBeStrictfp(ReferenceBinding type, AbstractMethodDeclaration methodDecl) { + String[] arguments = new String[] {new String(type.sourceName()), new String(methodDecl.selector)}; + this.handle( + IProblem.NativeMethodsCannotBeStrictfp, + arguments, + arguments, + methodDecl.sourceStart, + methodDecl.sourceEnd); +} +public void needImplementation() { + this.abortDueToInternalError(Util.bind("abort.missingCode")); //$NON-NLS-1$ +} +public void needToEmulateFieldReadAccess(FieldBinding field, ASTNode location) { + this.handle( + IProblem.NeedToEmulateFieldReadAccess, + new String[] {new String(field.declaringClass.readableName()), new String(field.name)}, + new String[] {new String(field.declaringClass.shortReadableName()), new String(field.name)}, + location.sourceStart, + location.sourceEnd); +} +public void needToEmulateFieldWriteAccess(FieldBinding field, ASTNode location) { + this.handle( + IProblem.NeedToEmulateFieldWriteAccess, + new String[] {new String(field.declaringClass.readableName()), new String(field.name)}, + new String[] {new String(field.declaringClass.shortReadableName()), new String(field.name)}, + location.sourceStart, + location.sourceEnd); +} +public void needToEmulateMethodAccess( + MethodBinding method, + ASTNode location) { + + if (method.isConstructor()) + this.handle( + IProblem.NeedToEmulateConstructorAccess, + new String[] { + new String(method.declaringClass.readableName()), + parametersAsString(method) + }, + new String[] { + new String(method.declaringClass.shortReadableName()), + parametersAsShortString(method) + }, + location.sourceStart, + location.sourceEnd); + else + this.handle( + IProblem.NeedToEmulateMethodAccess, + new String[] { + new String(method.declaringClass.readableName()), + new String(method.selector), + parametersAsString(method) + }, + new String[] { + new String(method.declaringClass.shortReadableName()), + new String(method.selector), + parametersAsShortString(method) + }, + location.sourceStart, + location.sourceEnd); +} +public void nestedClassCannotDeclareInterface(TypeDeclaration typeDecl) { + String[] arguments = new String[] {new String(typeDecl.name)}; + this.handle( + IProblem.CannotDefineInterfaceInLocalType, + arguments, + arguments, + typeDecl.sourceStart, + typeDecl.sourceEnd); +} +public void noMoreAvailableSpaceForArgument(LocalVariableBinding local, ASTNode location) { + String[] arguments = new String[]{ new String(local.name) }; + this.handle( + local instanceof SyntheticArgumentBinding + ? IProblem.TooManySyntheticArgumentSlots + : IProblem.TooManyArgumentSlots, + arguments, + arguments, + Abort | Error, + location.sourceStart, + location.sourceEnd); +} +public void noMoreAvailableSpaceForLocal(LocalVariableBinding local, ASTNode location) { + String[] arguments = new String[]{ new String(local.name) }; + this.handle( + IProblem.TooManyLocalVariableSlots, + arguments, + arguments, + Abort | Error, + location.sourceStart, + location.sourceEnd); +} +public void nonStaticAccessToStaticMethod(ASTNode location, MethodBinding method) { + this.handle( + IProblem.NonStaticAccessToStaticMethod, + new String[] {new String(method.declaringClass.readableName()), new String(method.selector), parametersAsString(method)}, + new String[] {new String(method.declaringClass.shortReadableName()), new String(method.selector), parametersAsShortString(method)}, + location.sourceStart, + location.sourceEnd); +} +public void nonStaticAccessToStaticField(ASTNode location, FieldBinding field) { + this.handle( + IProblem.NonStaticAccessToStaticField, + new String[] {new String(field.declaringClass.readableName()), new String(field.name)}, + new String[] {new String(field.declaringClass.shortReadableName()), new String(field.name)}, + location.sourceStart, + fieldLocation(field, location)); +} +public void noSuchEnclosingInstance(TypeBinding targetType, ASTNode location, boolean isConstructorCall) { + + int id; + + if (isConstructorCall) { + //28 = No enclosing instance of type {0} is available due to some intermediate constructor invocation + id = IProblem.EnclosingInstanceInConstructorCall; + } else if ((location instanceof ExplicitConstructorCall) + && ((ExplicitConstructorCall) location).accessMode == ExplicitConstructorCall.ImplicitSuper) { + //20 = No enclosing instance of type {0} is accessible to invoke the super constructor. Must define a constructor and explicitly qualify its super constructor invocation with an instance of {0} (e.g. x.super() where x is an instance of {0}). + id = IProblem.MissingEnclosingInstanceForConstructorCall; + } else if (location instanceof AllocationExpression + && (((AllocationExpression) location).binding.declaringClass.isMemberType() + || (((AllocationExpression) location).binding.declaringClass.isAnonymousType() + && ((AllocationExpression) location).binding.declaringClass.superclass().isMemberType()))) { + //21 = No enclosing instance of type {0} is accessible. Must qualify the allocation with an enclosing instance of type {0} (e.g. x.new A() where x is an instance of {0}). + id = IProblem.MissingEnclosingInstance; + } else { // default + //22 = No enclosing instance of the type {0} is accessible in scope + id = IProblem.IncorrectEnclosingInstanceReference; + } + + this.handle( + id, + new String[] { new String(targetType.readableName())}, + new String[] { new String(targetType.shortReadableName())}, + location.sourceStart, + location.sourceEnd); +} +public void notCompatibleTypesError(EqualExpression expression, TypeBinding leftType, TypeBinding rightType) { + String leftName = new String(leftType.readableName()); + String rightName = new String(rightType.readableName()); + String leftShortName = new String(leftType.shortReadableName()); + String rightShortName = new String(rightType.shortReadableName()); + if (leftShortName.equals(rightShortName)){ + leftShortName = leftName; + rightShortName = rightName; + } + this.handle( + IProblem.IncompatibleTypesInEqualityOperator, + new String[] {leftName, rightName }, + new String[] {leftShortName, rightShortName }, + expression.sourceStart, + expression.sourceEnd); +} +public void notCompatibleTypesError(InstanceOfExpression expression, TypeBinding leftType, TypeBinding rightType) { + String leftName = new String(leftType.readableName()); + String rightName = new String(rightType.readableName()); + String leftShortName = new String(leftType.shortReadableName()); + String rightShortName = new String(rightType.shortReadableName()); + if (leftShortName.equals(rightShortName)){ + leftShortName = leftName; + rightShortName = rightName; + } + this.handle( + IProblem.IncompatibleTypesInConditionalOperator, + new String[] {leftName, rightName }, + new String[] {leftShortName, rightShortName }, + expression.sourceStart, + expression.sourceEnd); +} +public void objectCannotHaveSuperTypes(SourceTypeBinding type) { + this.handle( + IProblem.ObjectCannotHaveSuperTypes, + NoArgument, + NoArgument, + type.sourceStart(), + type.sourceEnd()); +} +public void operatorOnlyValidOnNumericType(CompoundAssignment assignment, TypeBinding leftType, TypeBinding rightType) { + String leftName = new String(leftType.readableName()); + String rightName = new String(rightType.readableName()); + String leftShortName = new String(leftType.shortReadableName()); + String rightShortName = new String(rightType.shortReadableName()); + if (leftShortName.equals(rightShortName)){ + leftShortName = leftName; + rightShortName = rightName; + } + this.handle( + IProblem.TypeMismatch, + new String[] {leftName, rightName }, + new String[] {leftShortName, rightShortName }, + assignment.sourceStart, + assignment.sourceEnd); +} +public void overridesDeprecatedMethod(MethodBinding localMethod, MethodBinding inheritedMethod) { + this.handle( + IProblem.OverridingDeprecatedMethod, + new String[] { + new String( + CharOperation.concat( + localMethod.declaringClass.readableName(), + localMethod.readableName(), + '.')), + new String(inheritedMethod.declaringClass.readableName())}, + new String[] { + new String( + CharOperation.concat( + localMethod.declaringClass.shortReadableName(), + localMethod.shortReadableName(), + '.')), + new String(inheritedMethod.declaringClass.shortReadableName())}, + localMethod.sourceStart(), + localMethod.sourceEnd()); +} +public void overridesPackageDefaultMethod(MethodBinding localMethod, MethodBinding inheritedMethod) { + this.handle( + IProblem.OverridingNonVisibleMethod, + new String[] { + new String( + CharOperation.concat( + localMethod.declaringClass.readableName(), + localMethod.readableName(), + '.')), + new String(inheritedMethod.declaringClass.readableName())}, + new String[] { + new String( + CharOperation.concat( + localMethod.declaringClass.shortReadableName(), + localMethod.shortReadableName(), + '.')), + new String(inheritedMethod.declaringClass.shortReadableName())}, + localMethod.sourceStart(), + localMethod.sourceEnd()); +} +public void packageCollidesWithType(CompilationUnitDeclaration compUnitDecl) { + String[] arguments = new String[] {CharOperation.toString(compUnitDecl.currentPackage.tokens)}; + this.handle( + IProblem.PackageCollidesWithType, + arguments, + arguments, + compUnitDecl.currentPackage.sourceStart, + compUnitDecl.currentPackage.sourceEnd); +} +public void packageIsNotExpectedPackage(CompilationUnitDeclaration compUnitDecl) { + String[] arguments = new String[] {CharOperation.toString(compUnitDecl.compilationResult.compilationUnit.getPackageName())}; + this.handle( + IProblem.PackageIsNotExpectedPackage, + arguments, + arguments, + compUnitDecl.currentPackage == null ? 0 : compUnitDecl.currentPackage.sourceStart, + compUnitDecl.currentPackage == null ? 0 : compUnitDecl.currentPackage.sourceEnd); +} +private String parametersAsString(MethodBinding method) { + TypeBinding[] params = method.parameters; + StringBuffer buffer = new StringBuffer(); + for (int i = 0, length = params.length; i < length; i++) { + if (i != 0) + buffer.append(", "); //$NON-NLS-1$ + buffer.append(new String(params[i].readableName())); + } + return buffer.toString(); +} +private String parametersAsShortString(MethodBinding method) { + TypeBinding[] params = method.parameters; + StringBuffer buffer = new StringBuffer(); + for (int i = 0, length = params.length; i < length; i++) { + if (i != 0) + buffer.append(", "); //$NON-NLS-1$ + buffer.append(new String(params[i].shortReadableName())); + } + return buffer.toString(); +} +public void parseError( + int startPosition, + int endPosition, + int currentToken, + char[] currentTokenSource, + String errorTokenName, + String[] possibleTokens) { + + if (possibleTokens.length == 0) { //no suggestion available + if (isKeyword(currentToken)) { + String[] arguments = new String[] {new String(currentTokenSource)}; + this.handle( + IProblem.ParsingErrorOnKeywordNoSuggestion, + arguments, + arguments, + // this is the current -invalid- token position + startPosition, + endPosition); + return; + } else { + String[] arguments = new String[] {errorTokenName}; + this.handle( + IProblem.ParsingErrorNoSuggestion, + arguments, + arguments, + // this is the current -invalid- token position + startPosition, + endPosition); + return; + } + } + + //build a list of probable right tokens + StringBuffer list = new StringBuffer(20); + for (int i = 0, max = possibleTokens.length; i < max; i++) { + if (i > 0) + list.append(", "); //$NON-NLS-1$ + list.append('"'); + list.append(possibleTokens[i]); + list.append('"'); + } + + if (isKeyword(currentToken)) { + String[] arguments = new String[] {new String(currentTokenSource), list.toString()}; + this.handle( + IProblem.ParsingErrorOnKeyword, + arguments, + arguments, + // this is the current -invalid- token position + startPosition, + endPosition); + return; + } + //extract the literal when it's a literal + if (isLiteral(currentToken) || + isIdentifier(currentToken)) { //$NON-NLS-1$ + errorTokenName = new String(currentTokenSource); + } + + String[] arguments = new String[] {errorTokenName, list.toString()}; + this.handle( + IProblem.ParsingError, + arguments, + arguments, + // this is the current -invalid- token position + startPosition, + endPosition); +} +public void possibleAccidentalBooleanAssignment(Assignment assignment) { + String[] arguments = new String[] {}; + this.handle( + IProblem.PossibleAccidentalBooleanAssignment, + arguments, + arguments, + assignment.sourceStart, + assignment.sourceEnd); +} +public void publicClassMustMatchFileName(CompilationUnitDeclaration compUnitDecl, TypeDeclaration typeDecl) { + this.referenceContext = typeDecl; // report the problem against the type not the entire compilation unit + String[] arguments = new String[] {new String(compUnitDecl.getFileName()), new String(typeDecl.name)}; + this.handle( + IProblem.PublicClassMustMatchFileName, + arguments, + arguments, + typeDecl.sourceStart, + typeDecl.sourceEnd, + compUnitDecl.compilationResult); +} +public void recursiveConstructorInvocation(ExplicitConstructorCall constructorCall) { + + this.handle( + IProblem.RecursiveConstructorInvocation, + new String[] { + new String(constructorCall.binding.declaringClass.readableName()), + parametersAsString(constructorCall.binding) + }, + new String[] { + new String(constructorCall.binding.declaringClass.shortReadableName()), + parametersAsShortString(constructorCall.binding) + }, + constructorCall.sourceStart, + constructorCall.sourceEnd); +} + +public void redefineArgument(Argument arg) { + String[] arguments = new String[] {new String(arg.name)}; + this.handle( + IProblem.RedefinedArgument, + arguments, + arguments, + arg.sourceStart, + arg.sourceEnd); +} +public void redefineLocal(LocalDeclaration localDecl) { + String[] arguments = new String[] {new String(localDecl.name)}; + this.handle( + IProblem.RedefinedLocal, + arguments, + arguments, + localDecl.sourceStart, + localDecl.sourceEnd); +} +public void referenceMustBeArrayTypeAt(TypeBinding arrayType, ArrayReference arrayRef) { + this.handle( + IProblem.ArrayReferenceRequired, + new String[] {new String(arrayType.readableName())}, + new String[] {new String(arrayType.shortReadableName())}, + arrayRef.sourceStart, + arrayRef.sourceEnd); +} +public void returnTypeCannotBeVoidArray(SourceTypeBinding type, MethodDeclaration methodDecl) { + String[] arguments = new String[] {new String(methodDecl.selector)}; + this.handle( + IProblem.ReturnTypeCannotBeVoidArray, + arguments, + arguments, + methodDecl.sourceStart, + methodDecl.sourceEnd); +} +public void returnTypeProblem(SourceTypeBinding type, MethodDeclaration methodDecl, TypeBinding expectedType) { + int problemId = expectedType.problemId(); + int id; + switch (problemId) { + case NotFound : // 1 + id = IProblem.ReturnTypeNotFound; + break; + case NotVisible : // 2 + id = IProblem.ReturnTypeNotVisible; + break; + case Ambiguous : // 3 + id = IProblem.ReturnTypeAmbiguous; + break; + case InternalNameProvided : // 4 + id = IProblem.ReturnTypeInternalNameProvided; + break; + case InheritedNameHidesEnclosingName : // 5 + id = IProblem.ReturnTypeInheritedNameHidesEnclosingName; + break; + case NoError : // 0 + default : + needImplementation(); // want to fail to see why we were here... + return; + } + this.handle( + id, + new String[] {new String(methodDecl.selector), new String(expectedType.readableName())}, + new String[] {new String(methodDecl.selector), new String(expectedType.shortReadableName())}, + methodDecl.returnType.sourceStart, + methodDecl.returnType.sourceEnd); +} +public void scannerError(Parser parser, String errorTokenName) { + Scanner scanner = parser.scanner; + + int flag = IProblem.ParsingErrorNoSuggestion; + int startPos = scanner.startPosition; + + //special treatment for recognized errors.... + if (errorTokenName.equals(Scanner.END_OF_SOURCE)) + flag = IProblem.EndOfSource; + else if (errorTokenName.equals(Scanner.INVALID_HEXA)) + flag = IProblem.InvalidHexa; + else if (errorTokenName.equals(Scanner.INVALID_OCTAL)) + flag = IProblem.InvalidOctal; + else if (errorTokenName.equals(Scanner.INVALID_CHARACTER_CONSTANT)) + flag = IProblem.InvalidCharacterConstant; + else if (errorTokenName.equals(Scanner.INVALID_ESCAPE)) + flag = IProblem.InvalidEscape; + else if (errorTokenName.equals(Scanner.INVALID_UNICODE_ESCAPE)){ + flag = IProblem.InvalidUnicodeEscape; + // better locate the error message + char[] source = scanner.source; + int checkPos = scanner.currentPosition - 1; + if (checkPos >= source.length) checkPos = source.length - 1; + while (checkPos >= startPos){ + if (source[checkPos] == '\\') break; + checkPos --; + } + startPos = checkPos; + } else if (errorTokenName.equals(Scanner.INVALID_FLOAT)) + flag = IProblem.InvalidFloat; + else if (errorTokenName.equals(Scanner.UNTERMINATED_STRING)) + flag = IProblem.UnterminatedString; + else if (errorTokenName.equals(Scanner.UNTERMINATED_COMMENT)) + flag = IProblem.UnterminatedComment; + else if (errorTokenName.equals(Scanner.INVALID_CHAR_IN_STRING)) + flag = IProblem.UnterminatedString; + else if (errorTokenName.equals(Scanner.INVALID_INPUT)) + flag = IProblem.InvalidInput; + + String[] arguments = flag == IProblem.ParsingErrorNoSuggestion + ? new String[] {errorTokenName} + : NoArgument; + this.handle( + flag, + arguments, + arguments, + // this is the current -invalid- token position + startPos, + scanner.currentPosition - 1, + parser.compilationUnit.compilationResult); +} +public void shouldReturn(TypeBinding returnType, ASTNode location) { + this.handle( + IProblem.ShouldReturnValue, + new String[] { new String (returnType.readableName())}, + new String[] { new String (returnType.shortReadableName())}, + location.sourceStart, + location.sourceEnd); +} +public void signalNoImplicitStringConversionForCharArrayExpression(Expression expression) { + this.handle( + IProblem.NoImplicitStringConversionForCharArrayExpression, + NoArgument, + NoArgument, + expression.sourceStart, + expression.sourceEnd); +} +public void staticAndInstanceConflict(MethodBinding currentMethod, MethodBinding inheritedMethod) { + if (currentMethod.isStatic()) + this.handle( + // This static method cannot hide the instance method from %1 + // 8.4.6.4 - If a class inherits more than one method with the same signature a static (non-abstract) method cannot hide an instance method. + IProblem.CannotHideAnInstanceMethodWithAStaticMethod, + new String[] {new String(inheritedMethod.declaringClass.readableName())}, + new String[] {new String(inheritedMethod.declaringClass.shortReadableName())}, + currentMethod.sourceStart(), + currentMethod.sourceEnd()); + else + this.handle( + // This instance method cannot override the static method from %1 + // 8.4.6.4 - If a class inherits more than one method with the same signature an instance (non-abstract) method cannot override a static method. + IProblem.CannotOverrideAStaticMethodWithAnInstanceMethod, + new String[] {new String(inheritedMethod.declaringClass.readableName())}, + new String[] {new String(inheritedMethod.declaringClass.shortReadableName())}, + currentMethod.sourceStart(), + currentMethod.sourceEnd()); +} +public void staticFieldAccessToNonStaticVariable(ASTNode location, FieldBinding field) { + String[] arguments = new String[] {new String(field.readableName())}; + this.handle( + IProblem.NonStaticFieldFromStaticInvocation, + arguments, + arguments, + location.sourceStart, + fieldLocation(field, location)); +} +public void staticInheritedMethodConflicts(SourceTypeBinding type, MethodBinding concreteMethod, MethodBinding[] abstractMethods) { + this.handle( + // The static method %1 conflicts with the abstract method in %2 + // 8.4.6.4 - If a class inherits more than one method with the same signature it is an error for one to be static (non-abstract) and the other abstract. + IProblem.StaticInheritedMethodConflicts, + new String[] { + new String(concreteMethod.readableName()), + new String(abstractMethods[0].declaringClass.readableName())}, + new String[] { + new String(concreteMethod.readableName()), + new String(abstractMethods[0].declaringClass.shortReadableName())}, + type.sourceStart(), + type.sourceEnd()); +} +public void stringConstantIsExceedingUtf8Limit(ASTNode location) { + this.handle( + IProblem.StringConstantIsExceedingUtf8Limit, + NoArgument, + NoArgument, + location.sourceStart, + location.sourceEnd); +} +public void superclassMustBeAClass(SourceTypeBinding type, TypeReference superclassRef, ReferenceBinding superType) { + this.handle( + IProblem.SuperclassMustBeAClass, + new String[] {new String(superType.readableName()), new String(type.sourceName())}, + new String[] {new String(superType.shortReadableName()), new String(type.sourceName())}, + superclassRef.sourceStart, + superclassRef.sourceEnd); +} +public void superfluousSemicolon(int sourceStart, int sourceEnd) { + this.handle( + IProblem.SuperfluousSemicolon, + NoArgument, + NoArgument, + sourceStart, + sourceEnd); +} +public void superinterfaceMustBeAnInterface(SourceTypeBinding type, TypeDeclaration typeDecl, ReferenceBinding superType) { + this.handle( + IProblem.SuperInterfaceMustBeAnInterface, + new String[] {new String(superType.readableName()), new String(type.sourceName())}, + new String[] {new String(superType.shortReadableName()), new String(type.sourceName())}, + typeDecl.sourceStart, + typeDecl.sourceEnd); +} +public void task(String tag, String message, String priority, int start, int end){ + this.handle( + IProblem.Task, + new String[] { tag, message, priority/*secret argument that is not surfaced in getMessage()*/}, + new String[] { tag, message, priority/*secret argument that is not surfaced in getMessage()*/}, + start, + end); +} +public void tooManyDimensions(ASTNode expression) { + this.handle( + IProblem.TooManyArrayDimensions, + NoArgument, + NoArgument, + expression.sourceStart, + expression.sourceEnd); +} +public void tooManyFields(TypeDeclaration typeDeclaration) { + this.handle( + IProblem.TooManyFields, + new String[]{ new String(typeDeclaration.binding.readableName())}, + new String[]{ new String(typeDeclaration.binding.shortReadableName())}, + Abort | Error, + typeDeclaration.sourceStart, + typeDeclaration.sourceEnd); +} +public void tooManyMethods(TypeDeclaration typeDeclaration) { + this.handle( + IProblem.TooManyMethods, + new String[]{ new String(typeDeclaration.binding.readableName())}, + new String[]{ new String(typeDeclaration.binding.shortReadableName())}, + Abort | Error, + typeDeclaration.sourceStart, + typeDeclaration.sourceEnd); +} +public void typeCastError(CastExpression expression, TypeBinding leftType, TypeBinding rightType) { + String leftName = new String(leftType.readableName()); + String rightName = new String(rightType.readableName()); + String leftShortName = new String(leftType.shortReadableName()); + String rightShortName = new String(rightType.shortReadableName()); + if (leftShortName.equals(rightShortName)){ + leftShortName = leftName; + rightShortName = rightName; + } + this.handle( + IProblem.IllegalCast, + new String[] { rightName, leftName }, + new String[] { rightShortName, leftShortName }, + expression.sourceStart, + expression.sourceEnd); +} +public void typeCollidesWithPackage(CompilationUnitDeclaration compUnitDecl, TypeDeclaration typeDecl) { + this.referenceContext = typeDecl; // report the problem against the type not the entire compilation unit + String[] arguments = new String[] {new String(compUnitDecl.getFileName()), new String(typeDecl.name)}; + this.handle( + IProblem.TypeCollidesWithPackage, + arguments, + arguments, + typeDecl.sourceStart, + typeDecl.sourceEnd, + compUnitDecl.compilationResult); +} +public void typeMismatchError(TypeBinding resultType, TypeBinding expectedType, ASTNode location) { + String resultTypeName = new String(resultType.readableName()); + String expectedTypeName = new String(expectedType.readableName()); + String resultTypeShortName = new String(resultType.shortReadableName()); + String expectedTypeShortName = new String(expectedType.shortReadableName()); + if (resultTypeShortName.equals(expectedTypeShortName)){ + resultTypeShortName = resultTypeName; + expectedTypeShortName = expectedTypeName; + } + this.handle( + IProblem.TypeMismatch, + new String[] {resultTypeName, expectedTypeName}, + new String[] {resultTypeShortName, expectedTypeShortName}, + location.sourceStart, + location.sourceEnd); +} +public void typeMismatchErrorActualTypeExpectedType(Expression expression, TypeBinding constantType, TypeBinding expectedType) { + String constantTypeName = new String(constantType.readableName()); + String expectedTypeName = new String(expectedType.readableName()); + String constantTypeShortName = new String(constantType.shortReadableName()); + String expectedTypeShortName = new String(expectedType.shortReadableName()); + if (constantTypeShortName.equals(expectedTypeShortName)){ + constantTypeShortName = constantTypeName; + expectedTypeShortName = expectedTypeName; + } + this.handle( + IProblem.TypeMismatch, + new String[] {constantTypeName, expectedTypeName}, + new String[] {constantTypeShortName, expectedTypeShortName}, + expression.sourceStart, + expression.sourceEnd); +} +public void undefinedLabel(BranchStatement statement) { + String[] arguments = new String[] {new String(statement.label)}; + this.handle( + IProblem.UndefinedLabel, + arguments, + arguments, + statement.sourceStart, + statement.sourceEnd); +} +public void undocumentedEmptyBlock(int blockStart, int blockEnd) { + String[] arguments = new String[] {}; + this.handle( + IProblem.UndocumentedEmptyBlock, + arguments, + arguments, + blockStart, + blockEnd); +} +public void unexpectedStaticModifierForField(SourceTypeBinding type, FieldDeclaration fieldDecl) { + String[] arguments = new String[] {new String(fieldDecl.name)}; + this.handle( + IProblem.UnexpectedStaticModifierForField, + arguments, + arguments, + fieldDecl.sourceStart, + fieldDecl.sourceEnd); +} +public void unexpectedStaticModifierForMethod(ReferenceBinding type, AbstractMethodDeclaration methodDecl) { + String[] arguments = new String[] {new String(type.sourceName()), new String(methodDecl.selector)}; + this.handle( + IProblem.UnexpectedStaticModifierForMethod, + arguments, + arguments, + methodDecl.sourceStart, + methodDecl.sourceEnd); +} +public void unhandledException(TypeBinding exceptionType, ASTNode location) { + + boolean insideDefaultConstructor = + (this.referenceContext instanceof ConstructorDeclaration) + && ((ConstructorDeclaration)this.referenceContext).isDefaultConstructor(); + boolean insideImplicitConstructorCall = + (location instanceof ExplicitConstructorCall) + && (((ExplicitConstructorCall) location).accessMode == ExplicitConstructorCall.ImplicitSuper); + + this.handle( + insideDefaultConstructor + ? IProblem.UnhandledExceptionInDefaultConstructor + : (insideImplicitConstructorCall + ? IProblem.UndefinedConstructorInImplicitConstructorCall + : IProblem.UnhandledException), + new String[] {new String(exceptionType.readableName())}, + new String[] {new String(exceptionType.shortReadableName())}, + location.sourceStart, + location.sourceEnd); +} +public void uninitializedBlankFinalField(FieldBinding binding, ASTNode location) { + String[] arguments = new String[] {new String(binding.readableName())}; + this.handle( + IProblem.UninitializedBlankFinalField, + arguments, + arguments, + location.sourceStart, + fieldLocation(binding, location)); +} +public void uninitializedLocalVariable(LocalVariableBinding binding, ASTNode location) { + String[] arguments = new String[] {new String(binding.readableName())}; + this.handle( + IProblem.UninitializedLocalVariable, + arguments, + arguments, + location.sourceStart, + location.sourceEnd); +} +public void unmatchedBracket(int position, ReferenceContext context, CompilationResult compilationResult) { + this.handle( + IProblem.UnmatchedBracket, + NoArgument, + NoArgument, + position, + position, + context, + compilationResult); +} +public void unnecessaryCast(CastExpression castExpression) { + TypeBinding castedExpressionType = castExpression.expression.resolvedType; + this.handle( + IProblem.UnnecessaryCast, + new String[]{ new String(castedExpressionType.readableName()), new String(castExpression.resolvedType.readableName())}, + new String[]{ new String(castedExpressionType.shortReadableName()), new String(castExpression.resolvedType.shortReadableName())}, + castExpression.sourceStart, + castExpression.sourceEnd); +} +public void unnecessaryCastForArgument(CastExpression castExpression, TypeBinding parameterType) { + TypeBinding castedExpressionType = castExpression.expression.resolvedType; + this.handle( + IProblem.UnnecessaryArgumentCast, + new String[]{ new String(castedExpressionType.readableName()), new String(castExpression.resolvedType.readableName()), new String(parameterType.readableName())}, + new String[]{ new String(castedExpressionType.shortReadableName()), new String(castExpression.resolvedType.shortReadableName()), new String(parameterType.shortReadableName())}, + castExpression.sourceStart, + castExpression.sourceEnd); +} +public void unnecessaryInstanceof(InstanceOfExpression instanceofExpression, TypeBinding checkType) { + TypeBinding expressionType = instanceofExpression.expression.resolvedType; + this.handle( + IProblem.UnnecessaryInstanceof, + new String[]{ new String(expressionType.readableName()), new String(checkType.readableName())}, + new String[]{ new String(expressionType.shortReadableName()), new String(checkType.shortReadableName())}, + instanceofExpression.sourceStart, + instanceofExpression.sourceEnd); +} +public void unqualifiedFieldAccess(NameReference reference, FieldBinding field) { + int end = reference.sourceEnd; + if (reference instanceof QualifiedNameReference) { + QualifiedNameReference qref = (QualifiedNameReference) reference; + end = (int) qref.sourcePositions[0]; + } + this.handle( + IProblem.UnqualifiedFieldAccess, + new String[] {new String(field.declaringClass.readableName()), new String(field.name)}, + new String[] {new String(field.declaringClass.shortReadableName()), new String(field.name)}, + reference.sourceStart, + end); +} +public void unnecessaryElse(ASTNode location) { + this.handle( + IProblem.UnnecessaryElse, + NoArgument, + NoArgument, + location.sourceStart, + location.sourceEnd); +} +public void unnecessaryEnclosingInstanceSpecification(Expression expression, ReferenceBinding targetType) { + this.handle( + IProblem.IllegalEnclosingInstanceSpecification, + new String[]{ new String(targetType.readableName())}, + new String[]{ new String(targetType.shortReadableName())}, + expression.sourceStart, + expression.sourceEnd); +} +public void unreachableCatchBlock(ReferenceBinding exceptionType, ASTNode location) { + this.handle( + IProblem.UnreachableCatch, + new String[] { + new String(exceptionType.readableName()), + }, + new String[] { + new String(exceptionType.shortReadableName()), + }, + location.sourceStart, + location.sourceEnd); +} +public void unreachableCode(Statement statement) { + this.handle( + IProblem.CodeCannotBeReached, + NoArgument, + NoArgument, + statement.sourceStart, + statement.sourceEnd); +} +public void unresolvableReference(NameReference nameRef, Binding binding) { + int severity = Error; +/* also need to check that the searchedType is the receiver type + if (binding instanceof ProblemBinding) { + ProblemBinding problem = (ProblemBinding) binding; + if (problem.searchType != null && problem.searchType.isHierarchyInconsistent()) + severity = SecondaryError; + } +*/ + String[] arguments = new String[] {new String(binding.readableName())}; + int end = nameRef.sourceEnd; + if (nameRef instanceof QualifiedNameReference) { + QualifiedNameReference ref = (QualifiedNameReference) nameRef; + if (ref.indexOfFirstFieldBinding >= 1) + end = (int) ref.sourcePositions[ref.indexOfFirstFieldBinding - 1]; + } + this.handle( + IProblem.UndefinedName, + arguments, + arguments, + severity, + nameRef.sourceStart, + end); +} +public void unusedArgument(LocalDeclaration localDecl) { + + String[] arguments = new String[] {new String(localDecl.name)}; + this.handle( + IProblem.ArgumentIsNeverUsed, + arguments, + arguments, + localDecl.sourceStart, + localDecl.sourceEnd); +} +public void unusedDeclaredThrownException(ReferenceBinding exceptionType, AbstractMethodDeclaration method, ASTNode location) { + if (method.isConstructor()) { + this.handle( + IProblem.UnusedConstructorDeclaredThrownException, + new String[] { + new String(method.binding.declaringClass.readableName()), + parametersAsString(method.binding), + new String(exceptionType.readableName()), + }, + new String[] { + new String(method.binding.declaringClass.shortReadableName()), + parametersAsShortString(method.binding), + new String(exceptionType.shortReadableName()), + }, + location.sourceStart, + location.sourceEnd); + } else { + this.handle( + IProblem.UnusedMethodDeclaredThrownException, + new String[] { + new String(method.binding.declaringClass.readableName()), + new String(method.selector), + parametersAsString(method.binding), + new String(exceptionType.readableName()), + }, + new String[] { + new String(method.binding.declaringClass.shortReadableName()), + new String(method.selector), + parametersAsShortString(method.binding), + new String(exceptionType.shortReadableName()), + }, + location.sourceStart, + location.sourceEnd); + } +} +public void unusedImport(ImportReference importRef) { + String[] arguments = new String[] { CharOperation.toString(importRef.tokens) }; + this.handle( + IProblem.UnusedImport, + arguments, + arguments, + importRef.sourceStart, + importRef.sourceEnd); +} +public void unusedLocalVariable(LocalDeclaration localDecl) { + String[] arguments = new String[] {new String(localDecl.name)}; + this.handle( + IProblem.LocalVariableIsNeverUsed, + arguments, + arguments, + localDecl.sourceStart, + localDecl.sourceEnd); +} +public void unusedPrivateConstructor(ConstructorDeclaration constructorDecl) { + + if (computeSeverity(IProblem.UnusedPrivateConstructor) == Ignore) return; + + // no complaint for no-arg constructors (or default ones) - known pattern to block instantiation + if (constructorDecl.arguments == null || constructorDecl.arguments.length == 0) return; + + MethodBinding constructor = constructorDecl.binding; + this.handle( + IProblem.UnusedPrivateConstructor, + new String[] { + new String(constructor.declaringClass.readableName()), + parametersAsString(constructor) + }, + new String[] { + new String(constructor.declaringClass.shortReadableName()), + parametersAsShortString(constructor) + }, + constructorDecl.sourceStart, + constructorDecl.sourceEnd); +} +public void unusedPrivateField(FieldDeclaration fieldDecl) { + + if (computeSeverity(IProblem.UnusedPrivateField) == Ignore) return; + + FieldBinding field = fieldDecl.binding; + + if (CharOperation.equals(TypeConstants.SERIALVERSIONUID, field.name) + && field.isStatic() + && field.isFinal() + && BaseTypes.LongBinding == field.type) { + return; // do not report unused serialVersionUID field + } + if (CharOperation.equals(TypeConstants.SERIALPERSISTENTFIELDS, field.name) + && field.isStatic() + && field.isFinal() + && field.type.dimensions() == 1 + && CharOperation.equals(TypeConstants.CharArray_JAVA_IO_OBJECTSTREAMFIELD, field.type.leafComponentType().readableName())) { + return; // do not report unused serialPersistentFields field + } + this.handle( + IProblem.UnusedPrivateField, + new String[] { + new String(field.declaringClass.readableName()), + new String(field.name), + }, + new String[] { + new String(field.declaringClass.shortReadableName()), + new String(field.name), + }, + fieldDecl.sourceStart, + fieldDecl.sourceEnd); +} +public void unusedPrivateMethod(AbstractMethodDeclaration methodDecl) { + + if (computeSeverity(IProblem.UnusedPrivateMethod) == Ignore) return; + + MethodBinding method = methodDecl.binding; + + // no report for serialization support 'void readObject(ObjectInputStream)' + if (!method.isStatic() + && BaseTypes.VoidBinding == method.returnType + && method.parameters.length == 1 + && method.parameters[0].dimensions() == 0 + && CharOperation.equals(method.selector, TypeConstants.READOBJECT) + && CharOperation.equals(TypeConstants.CharArray_JAVA_IO_OBJECTINPUTSTREAM, method.parameters[0].readableName())) { + return; + } + // no report for serialization support 'void writeObject(ObjectOutputStream)' + if (!method.isStatic() + && BaseTypes.VoidBinding == method.returnType + && method.parameters.length == 1 + && method.parameters[0].dimensions() == 0 + && CharOperation.equals(method.selector, TypeConstants.WRITEOBJECT) + && CharOperation.equals(TypeConstants.CharArray_JAVA_IO_OBJECTOUTPUTSTREAM, method.parameters[0].readableName())) { + return; + } + // no report for serialization support 'Object readResolve()' + if (!method.isStatic() + && TypeIds.T_Object == method.returnType.id + && method.parameters.length == 0 + && CharOperation.equals(method.selector, TypeConstants.READRESOLVE)) { + return; + } + // no report for serialization support 'Object writeReplace()' + if (!method.isStatic() + && TypeIds.T_Object == method.returnType.id + && method.parameters.length == 0 + && CharOperation.equals(method.selector, TypeConstants.WRITEREPLACE)) { + return; + } + this.handle( + IProblem.UnusedPrivateMethod, + new String[] { + new String(method.declaringClass.readableName()), + new String(method.selector), + parametersAsString(method) + }, + new String[] { + new String(method.declaringClass.shortReadableName()), + new String(method.selector), + parametersAsShortString(method) + }, + methodDecl.sourceStart, + methodDecl.sourceEnd); +} +public void unusedPrivateType(TypeDeclaration typeDecl) { + + if (computeSeverity(IProblem.UnusedPrivateType) == Ignore) return; + + ReferenceBinding type = typeDecl.binding; + this.handle( + IProblem.UnusedPrivateType, + new String[] { + new String(type.readableName()), + }, + new String[] { + new String(type.shortReadableName()), + }, + typeDecl.sourceStart, + typeDecl.sourceEnd); +} +public void useAssertAsAnIdentifier(int sourceStart, int sourceEnd) { + this.handle( + IProblem.UseAssertAsAnIdentifier, + NoArgument, + NoArgument, + sourceStart, + sourceEnd); +} + +public void variableTypeCannotBeVoid(AbstractVariableDeclaration varDecl) { + String[] arguments = new String[] {new String(varDecl.name)}; + this.handle( + IProblem.VariableTypeCannotBeVoid, + arguments, + arguments, + varDecl.sourceStart, + varDecl.sourceEnd); +} +public void variableTypeCannotBeVoidArray(AbstractVariableDeclaration varDecl) { + String[] arguments = new String[] {new String(varDecl.name)}; + this.handle( + IProblem.VariableTypeCannotBeVoidArray, + arguments, + arguments, + varDecl.sourceStart, + varDecl.sourceEnd); +} +public void visibilityConflict(MethodBinding currentMethod, MethodBinding inheritedMethod) { + this.handle( + // Cannot reduce the visibility of the inherited method from %1 + // 8.4.6.3 - The access modifier of an hiding method must provide at least as much access as the hidden method. + // 8.4.6.3 - The access modifier of an overiding method must provide at least as much access as the overriden method. + IProblem.MethodReducesVisibility, + new String[] {new String(inheritedMethod.declaringClass.readableName())}, + new String[] {new String(inheritedMethod.declaringClass.shortReadableName())}, + currentMethod.sourceStart(), + currentMethod.sourceEnd()); +} +public void nonExternalizedStringLiteral(ASTNode location) { + this.handle( + IProblem.NonExternalizedStringLiteral, + NoArgument, + NoArgument, + location.sourceStart, + location.sourceEnd); +} + +public void noMoreAvailableSpaceForConstant(TypeDeclaration typeDeclaration) { + this.handle( + IProblem.TooManyBytesForStringConstant, + new String[]{ new String(typeDeclaration.binding.readableName())}, + new String[]{ new String(typeDeclaration.binding.shortReadableName())}, + Abort | Error, + typeDeclaration.sourceStart, + typeDeclaration.sourceEnd); +} + +public void noMoreAvailableSpaceInConstantPool(TypeDeclaration typeDeclaration) { + this.handle( + IProblem.TooManyConstantsInConstantPool, + new String[]{ new String(typeDeclaration.binding.readableName())}, + new String[]{ new String(typeDeclaration.binding.shortReadableName())}, + Abort | Error, + typeDeclaration.sourceStart, + typeDeclaration.sourceEnd); +} + +private boolean isKeyword(int token) { + switch(token) { + case TerminalTokens.TokenNameabstract: + case TerminalTokens.TokenNameassert: + case TerminalTokens.TokenNamebyte: + case TerminalTokens.TokenNamebreak: + case TerminalTokens.TokenNameboolean: + case TerminalTokens.TokenNamecase: + case TerminalTokens.TokenNamechar: + case TerminalTokens.TokenNamecatch: + case TerminalTokens.TokenNameclass: + case TerminalTokens.TokenNamecontinue: + case TerminalTokens.TokenNamedo: + case TerminalTokens.TokenNamedouble: + case TerminalTokens.TokenNamedefault: + case TerminalTokens.TokenNameelse: + case TerminalTokens.TokenNameextends: + case TerminalTokens.TokenNamefor: + case TerminalTokens.TokenNamefinal: + case TerminalTokens.TokenNamefloat: + case TerminalTokens.TokenNamefalse: + case TerminalTokens.TokenNamefinally: + case TerminalTokens.TokenNameif: + case TerminalTokens.TokenNameint: + case TerminalTokens.TokenNameimport: + case TerminalTokens.TokenNameinterface: + case TerminalTokens.TokenNameimplements: + case TerminalTokens.TokenNameinstanceof: + case TerminalTokens.TokenNamelong: + case TerminalTokens.TokenNamenew: + case TerminalTokens.TokenNamenull: + case TerminalTokens.TokenNamenative: + case TerminalTokens.TokenNamepublic: + case TerminalTokens.TokenNamepackage: + case TerminalTokens.TokenNameprivate: + case TerminalTokens.TokenNameprotected: + case TerminalTokens.TokenNamereturn: + case TerminalTokens.TokenNameshort: + case TerminalTokens.TokenNamesuper: + case TerminalTokens.TokenNamestatic: + case TerminalTokens.TokenNameswitch: + case TerminalTokens.TokenNamestrictfp: + case TerminalTokens.TokenNamesynchronized: + case TerminalTokens.TokenNametry: + case TerminalTokens.TokenNamethis: + case TerminalTokens.TokenNametrue: + case TerminalTokens.TokenNamethrow: + case TerminalTokens.TokenNamethrows: + case TerminalTokens.TokenNametransient: + case TerminalTokens.TokenNamevoid: + case TerminalTokens.TokenNamevolatile: + case TerminalTokens.TokenNamewhile: + return true; + default: + return false; + } +} + +private boolean isLiteral(int token) { + switch(token) { + case TerminalTokens.TokenNameIntegerLiteral: + case TerminalTokens.TokenNameLongLiteral: + case TerminalTokens.TokenNameFloatingPointLiteral: + case TerminalTokens.TokenNameDoubleLiteral: + case TerminalTokens.TokenNameStringLiteral: + case TerminalTokens.TokenNameCharacterLiteral: + return true; + default: + return false; + } +} + +private boolean isIdentifier(int token) { + return token == TerminalTokens.TokenNameIdentifier; +} + +private void syntaxError( + int id, + int startPosition, + int endPosition, + int currentKind, + char[] currentTokenSource, + String errorTokenName, + String expectedToken) { + + String eTokenName; + if (isKeyword(currentKind) || + isLiteral(currentKind) || + isIdentifier(currentKind)) { //$NON-NLS-1$ + eTokenName = new String(currentTokenSource); + } else { + eTokenName = errorTokenName; + } + + String[] arguments; + if(expectedToken != null) { + arguments = new String[] {eTokenName, expectedToken}; + } else { + arguments = new String[] {eTokenName}; + } + this.handle( + id, + arguments, + arguments, + startPosition, + endPosition); +} + +public void parseErrorInsertBeforeToken( + int start, + int end, + int currentKind, + char[] errorTokenSource, + String errorTokenName, + String expectedToken){ + this.syntaxError( + IProblem.ParsingErrorInsertTokenBefore, + start, + end, + currentKind, + errorTokenSource, + errorTokenName, + expectedToken); +} +public void parseErrorInsertAfterToken( + int start, + int end, + int currentKind, + char[] errorTokenSource, + String errorTokenName, + String expectedToken){ + this.syntaxError( + IProblem.ParsingErrorInsertTokenAfter, + start, + end, + currentKind, + errorTokenSource, + errorTokenName, + expectedToken); +} +public void parseErrorDeleteToken( + int start, + int end, + int currentKind, + char[] errorTokenSource, + String errorTokenName){ + this.syntaxError( + IProblem.ParsingErrorDeleteToken, + start, + end, + currentKind, + errorTokenSource, + errorTokenName, + null); +} +public void parseErrorReplaceToken( + int start, + int end, + int currentKind, + char[] errorTokenSource, + String errorTokenName, + String expectedToken){ + this.syntaxError( + IProblem.ParsingError, + start, + end, + currentKind, + errorTokenSource, + errorTokenName, + expectedToken); +} +public void parseErrorInvalidToken( + int start, + int end, + int currentKind, + char[] errorTokenSource, + String errorTokenName, + String expectedToken){ + this.syntaxError( + IProblem.ParsingErrorInvalidToken, + start, + end, + currentKind, + errorTokenSource, + errorTokenName, + expectedToken); +} +public void parseErrorUnexpectedEnd( + int start, + int end){ + + String[] arguments; + if(this.referenceContext instanceof ConstructorDeclaration) { + arguments = new String[] {Util.bind("parser.endOfConstructor")}; //$NON-NLS-1$ + } else if(this.referenceContext instanceof MethodDeclaration) { + arguments = new String[] {Util.bind("parser.endOfMethod")}; //$NON-NLS-1$ + } else if(this.referenceContext instanceof TypeDeclaration) { + arguments = new String[] {Util.bind("parser.endOfInitializer")}; //$NON-NLS-1$ + } else { + arguments = new String[] {Util.bind("parser.endOfFile")}; //$NON-NLS-1$ + } + this.handle( + IProblem.ParsingErrorUnexpectedEOF, + arguments, + arguments, + start, + end); +} +public void parseErrorMergeTokens( + int start, + int end, + String expectedToken){ + String[] arguments = new String[] {expectedToken}; + this.handle( + IProblem.ParsingErrorMergeTokens, + arguments, + arguments, + start, + end); +} +public void parseErrorMisplacedConstruct( + int start, + int end){ + this.handle( + IProblem.ParsingErrorMisplacedConstruct, + NoArgument, + NoArgument, + start, + end); +} +public void parseErrorNoSuggestion( + int start, + int end, + int currentKind, + char[] errorTokenSource, + String errorTokenName){ + this.syntaxError( + IProblem.ParsingErrorNoSuggestion, + start, + end, + currentKind, + errorTokenSource, + errorTokenName, + null); +} +public void parseErrorDeleteTokens( + int start, + int end){ + this.handle( + IProblem.ParsingErrorDeleteTokens, + NoArgument, + NoArgument, + start, + end); +} +public void parseErrorNoSuggestionForTokens( + int start, + int end){ + this.handle( + IProblem.ParsingErrorNoSuggestionForTokens, + NoArgument, + NoArgument, + start, + end); +} +public void parseErrorReplaceTokens( + int start, + int end, + String expectedToken){ + String[] arguments = new String[] {expectedToken}; + this.handle( + IProblem.ParsingErrorReplaceTokens, + arguments, + arguments, + start, + end); +} +public void parseErrorInsertToComplete( + int start, + int end, + String inserted, + String completed){ + String[] arguments = new String[] {inserted, completed}; + this.handle( + IProblem.ParsingErrorInsertToComplete, + arguments, + arguments, + start, + end); +} +public void parseErrorInsertToCompleteScope( + int start, + int end, + String inserted){ + String[] arguments = new String[] {inserted}; + this.handle( + IProblem.ParsingErrorInsertToCompleteScope, + arguments, + arguments, + start, + end); +} +public void parseErrorInsertToCompletePhrase( + int start, + int end, + String inserted){ + String[] arguments = new String[] {inserted}; + this.handle( + IProblem.ParsingErrorInsertToCompletePhrase, + arguments, + arguments, + start, + end); +} +public void wrongSequenceOfExceptionTypesError(TryStatement statement, TypeBinding exceptionType, int under, TypeBinding hidingExceptionType) { + //the two catch block under and upper are in an incorrect order. + //under should be define BEFORE upper in the source + + TypeReference typeRef = statement.catchArguments[under].type; + this.handle( + IProblem.InvalidCatchBlockSequence, + new String[] { + new String(exceptionType.readableName()), + new String(hidingExceptionType.readableName()), + }, + new String[] { + new String(exceptionType.shortReadableName()), + new String(hidingExceptionType.shortReadableName()), + }, + typeRef.sourceStart, + typeRef.sourceEnd); +} + +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/problem/ProblemSeverities.java b/src/java/org/eclipse/jdt/internal/compiler/problem/ProblemSeverities.java new file mode 100644 index 0000000..d2cf193 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/problem/ProblemSeverities.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.problem; + +public interface ProblemSeverities { + + final int Ignore = -1; // during handling only + final int Warning = 0; // during handling only + + final int Error = 1; // when bit is set: problem is error, if not it is a warning + final int AbortCompilation = 2; + final int AbortCompilationUnit = 4; + final int AbortType = 8; + final int AbortMethod = 16; + final int Abort = 30; // 2r11110 + final int SecondaryError = 64; +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/problem/ShouldNotImplement.java b/src/java/org/eclipse/jdt/internal/compiler/problem/ShouldNotImplement.java new file mode 100644 index 0000000..a6533e5 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/problem/ShouldNotImplement.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.problem; + +/* + * Special unchecked exception type used + * to denote implementation that should never be reached. + * + * (internal only) + */ +public class ShouldNotImplement extends RuntimeException { + + private static final long serialVersionUID = 2669970476264283736L; // backward compatible + + public ShouldNotImplement(String message) { + super(message); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/problem/messages.properties b/src/java/org/eclipse/jdt/internal/compiler/problem/messages.properties new file mode 100644 index 0000000..e45ae5d --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/problem/messages.properties @@ -0,0 +1,381 @@ +############################################################################### +# Copyright (c) 2000, 2004 IBM Corporation and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Common Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/cpl-v10.html +# +# Contributors: +# IBM Corporation - initial API and implementation +############################################################################### +0 = {0} +1 = super cannot be used in java.lang.Object +2 = {0} cannot be resolved or is not a type +3 = The type {0} is not visible +4 = The type {0} is ambiguous +5 = The type {0} is deprecated +6 = The nested type {0} cannot be referenced using its binary name +7 = The private type {0} is never used locally + +15 = Incompatible operand types {0} and {1} +16 = Incompatible conditional operand types {0} and {1} +17 = Type mismatch: cannot convert from {0} to {1} +18 = The static member type {0}.{1} should be accessed directly + +20 = No enclosing instance of type {0} is accessible to invoke the super constructor. Must define a constructor and explicitly qualify its super constructor invocation with an instance of {0} (e.g. x.super() where x is an instance of {0}). +21 = No enclosing instance of type {0} is accessible. Must qualify the allocation with an enclosing instance of type {0} (e.g. x.new A() where x is an instance of {0}). +22 = No enclosing instance of the type {0} is accessible in scope +23 = Illegal enclosing instance specification for type {0} +24 = Cannot define static initializer in inner type {0} +25 = Cannot refer to a non-final variable {0} inside an inner class defined in a different method +26 = The member interface {0} can only be defined inside a top-level class or interface +27 = Cannot use an expression of the type {0} as a valid enclosing instance +28 = No enclosing instance of type {0} is available due to some intermediate constructor invocation +29 = An anonymous class cannot subclass the final class {0} + +50 = {0} cannot be resolved +51 = The local variable {0} may not have been initialized +52 = void is an invalid type for the variable {0} +53 = An array of void is an invalid type for the variable {0} +54 = An array of void is an invalid type +55 = Duplicate local variable {0} +56 = Duplicate parameter {0} +57 = The final local variable {0} may already have been assigned +58 = The final local variable {0} cannot be assigned. It must be blank and not using a compound assignment + +60 = The final local variable {0} cannot be assigned, since it is defined in an enclosing type +61 = The local variable {0} is never read +62 = The parameter {0} is never read +63 = The code of method {0}({1}) is exceeding the 65535 bytes limit +64 = The code for the static initializer is exceeding the 65535 bytes limit +65 = Too many parameters, parameter {0} is exceeding the limit of 255 words eligible for method parameters +66 = Too many local variables, local variable {0} is exceeding the limit of 65535 words eligible for method local variables +67 = Too many synthetic parameters, emulated parameter {0} is exceeding the limit of 255 words eligible for method parameters +68 = Too many array dimensions. Maximum is 255 +69 = The code of constructor {0}({1}) is exceeding the 65535 bytes limit +70 = {0} cannot be resolved or is not a field +71 = The field {0} is not visible +72 = The field {0} is ambiguous +73 = The field {0}.{1} is deprecated +74 = Cannot make a static reference to the non-static field {0} +75 = Cannot reference a field before it is defined +76 = The static field {0}.{1} should be accessed in a static way +77 = The private field {0}.{1} is never read locally +78 = The static field {0}.{1} should be accessed directly +79 = Unqualified access to the field {0}.{1} +80 = The final field {0}.{1} cannot be assigned. It must be blank in this context, not qualified and not in compound assignment +81 = The blank final field {0} may not have been initialized +82 = The final field {0} may already have been assigned + +90 = The local variable {0} is hiding another local variable defined in an enclosing type scope +91 = The local variable {0} is hiding a field from type {1} +92 = The field {0}.{1} is hiding another local variable defined in an enclosing type scope +93 = The field {0}.{1} is hiding a field from type {2} +94 = The parameter {0} is hiding another local variable defined in an enclosing type scope +95 = The parameter {0} is hiding a field from type {1} + +100 = The method {1}({2}) is undefined for the type {0} +101 = The method {1}({2}) from the type {0} is not visible +102 = The method {1}({2}) is ambiguous for the type {0} +103 = The method {1}({2}) from the type {0} is deprecated +104 = Cannot directly invoke the abstract method {1}({2}) for the type {0} +105 = Void methods cannot return a value +106 = Cannot return a void result +107 = This method requires a body instead of a semicolon +108 = This method must return a result of type {0} + +110 = This method has a constructor name +111 = Return type for the method is missing +112 = Native methods do not specify a body +113 = Abstract methods do not specify a body +114 = Cannot invoke {1}({2}) on the primitive type {0} +115 = The method {1}({2}) in the type {0} is not applicable for the arguments ({3}) +116 = Cannot invoke {1}({2}) on the array type {0} +117 = The static method {1}({2}) from the type {0} should be accessed in a static way +118 = The private method {1}({2}) from the type {0} is never used locally +119 = The static method {1}({2}) from the type {0} should be accessed directly + +130 = The constructor {0}({1}) is undefined +131 = The constructor {0}({1}) is not visible +132 = The constructor {0}({1}) is ambiguous +133 = The constructor {0}({1}) is deprecated +134 = The private constructor {0}({1}) is never used locally +135 = Cannot refer to an instance field {0} while explicitly invoking a constructor +136 = Cannot refer to an instance method while explicitly invoking a constructor +137 = Recursive constructor invocation {0}({1}) +138 = Cannot refer to ''this'' nor ''super'' while explicitly invoking a constructor +139 = Constructor call must be the first statement in a constructor +140 = Implicit super constructor {0}({1}) is undefined for default constructor. Must define an explicit constructor +141 = Implicit super constructor {0}({1}) is not visible for default constructor. Must define an explicit constructor +142 = Implicit super constructor {0}({1}) is ambiguous for default constructor. Must define an explicit constructor +143 = Implicit super constructor {0}({1}) is undefined. Must explicitly invoke another constructor +144 = Implicit super constructor {0}({1}) is not visible. Must explicitly invoke another constructor +145 = Implicit super constructor {0}({1}) is ambiguous. Must explicitly invoke another constructor +146 = Default constructor cannot handle exception type {0} thrown by implicit super constructor. Must define an explicit constructor +147 = Unhandled exception type {0} thrown by implicit super constructor + +150 = The type of the expression must be an array type but it resolved to {0} +151 = Must explicitly convert the char[] to a String +152 = String constant is exceeding the limit of 65535 bytes of UTF8 encoding +153 = case expressions must be constant expressions +154 = The literal {1} of type {0} is out of range +156 = Cannot cast from {0} to {1} +157 = Cannot instantiate the type {0}, since it is not a concrete class +158 = Cannot define dimension expressions when an array initializer is provided +159 = Variable must provide either dimension expressions or an array initializer +160 = The operator {0} is undefined for the argument type(s) {1} +161 = Unreachable code +162 = Cannot return from within an initializer +163 = Initializer does not complete normally +164 = Expression must return a value +165 = Unreachable catch block for {0}. Only more specific exceptions are thrown and handled by previous catch block(s). +166 = The default case is already defined +167 = Unreachable catch block for {0}. This exception is never thrown from the try statement body +168 = Unhandled exception type {0} +169 = case constant must be a char, byte, short, or int instead of {0} +170 = Duplicate case +171 = Duplicate label {0} +172 = break cannot be used outside of a loop or a switch +173 = continue cannot be used outside of a loop +174 = The label {0} is missing +175 = {0} is not a valid type''s argument for the synchronized statement +176 = null is not a valid argument for the synchronized statement +177 = Cannot throw null +178 = The assignment to variable {0} has no effect +179 = Possible accidental assignment in place of a comparison. A condition expression should not be reduced to an assignment +180 = Unnecessary semicolon +181 = Unnecessary cast to type {1} for expression of type {0} +182 = Unnecessary cast to type {1} for expression of type {0}. It is already compatible with the argument type {2} +183 = The expression of type {0} is already an instance of type {1} +184 = finally block does not complete normally +185 = The declared exception {3} is not actually thrown by the method {1}({2}) from type {0} +186 = The declared exception {2} is not actually thrown by the constructor {0}({1}) +187 = Unreachable catch block for {0}. It is already handled by the catch block for {1} +188 = Empty control-flow statement +189 = Statement unnecessarily nested within else clause. The corresponding then clause does not complete normally +190 = Read access to enclosing field {0}.{1} is emulated by a synthetic accessor method. Increasing its visibility will improve your performance +191 = Write access to enclosing field {0}.{1} is emulated by a synthetic accessor method. Increasing its visibility will improve your performance +192 = Access to enclosing method {1}({2}) from the type {0} is emulated by a synthetic accessor method. Increasing its visibility will improve your performance +193 = Access to enclosing constructor {0}({1}) is emulated by a synthetic accessor method. Increasing its visibility will improve your performance +195 = The method {1} is defined in an inherited type and an enclosing scope +196 = The field {0} is defined in an inherited type and an enclosing scope +197 = The type {0} is defined in an inherited type and an enclosing scope + +200 = Cannot use {0} in a static context +201 = The method {1}({2}) from the type {0} is not static +202 = Cannot specify an array dimension after an empty dimension +203 = Invalid cast type expression +204 = Syntax error on token "{0}", {1} expected +205 = Syntax error on token "{0}", no accurate correction available +206 = Invalid argument to operation ++/-- +207 = Interfaces cannot have constructors +208 = Array constants can only be used in initializers +209 = Syntax error on keyword "{0}"; {1} expected +210 = Syntax error on keyword "{0}", no accurate correction available + +220 = Unmatched bracket +221 = The primitive type {0} of {1} does not have a field {2} +222 = Invalid expression as statement +223 = The left-hand side of an assignment must be a variable +224 = Missing semicolon +225 = Invalid parenthesized expression + +230 = Syntax error on token "{0}", {1} expected before this token +231 = Syntax error on token "{0}", {1} expected after this token +232 = Syntax error on token "{0}", delete this token +233 = Syntax error on tokens, delete these tokens +234 = Syntax error on tokens, they can be merge to form {0} +235 = Syntax error on token "{0}", invalid {1} +236 = Syntax error on token(s), misplaced construct(s) +237 = Syntax error on tokens, {0} expected instead +238 = Syntax error on tokens, no accurate correction available +239 = Syntax error, unexpected {0} +240 = Syntax error, insert "{0}" to complete {1} +241 = Syntax error, insert "{0}" to complete scope +242 = Syntax error, insert "{0}" to complete phrase + +250 = Unexpected end of file +251 = Invalid hex literal number +252 = Invalid octal literal number +253 = Invalid character constant +254 = Invalid escape sequence (valid ones are \\b \\t \\n \\f \\r \\" \\'' \\\\ ) +255 = Invalid input +256 = Invalid unicode +257 = Invalid float literal number +258 = Null source string +259 = String literal is not properly closed by a double-quote +260 = Unexpected end of comment +261 = Non-externalized string literal; it should be followed by //$NON-NLS-$ + +300 = The interface {0} cannot define an initializer +301 = Duplicate modifier for the type {0} +302 = Illegal modifier for the class {0}; only public, abstract & final are permitted +303 = Illegal modifier for the interface {0}; only public & abstract are permitted +304 = Illegal modifier for the member class {0}; only public, protected, private, static, abstract & final are permitted +305 = Illegal modifier for the member interface {0}; only public, protected, private, static & abstract are permitted +306 = Illegal modifier for the local class {0}; only one of abstract or final is permitted +308 = The class {0} can be either abstract or final, not both +309 = The interface member type {0} can only be public +310 = The member type {0} can only set one of public / protected / private +311 = The member type {0} cannot be declared static; static types can only be declared in static or top level types +312 = The interface {0} cannot be the superclass of {1}; a superclass must be a class +313 = The type {1} cannot subclass the final class {0} +314 = Duplicate interface {0} for the type {1} +315 = The class {0} cannot be a superinterface of {1}; a superinterface must be an interface +316 = {1} causes a cycle - the type {0} cannot extend/implement itself or one of its own member types +317 = A cycle exists in the type hierarchy between {0} and {1} +318 = Nested type {0} hides an enclosing type +319 = Duplicate nested type {0} +320 = Cannot throw the type {0} +321 = The package {0} collides with a type +322 = The type {1} collides with a package +323 = The type {1} is already defined +324 = The type {0} cannot be resolved. It is indirectly referenced from required .class files +325 = The public type {1} must be defined in its own file +326 = A package must be specified in {0} or a default package created +327 = The hierarchy of the type {0} is inconsistent +328 = The declared package does not match the expected package {0} +329 = The type java.lang.Object cannot have a superclass or superinterfaces + +330 = {0} cannot be resolved or is not a valid superclass +331 = Superclass {0} is not visible +332 = Superclass {0} is ambiguous +333 = Superclass {0} cannot be referenced using its binary name +334 = Superclass {0} is defined in an inherited type and an enclosing scope +335 = {0} cannot be resolved or is not a valid superinterface +336 = Superinterface {0} is not visible +337 = Superinterface {0} is ambiguous +338 = Superinterface {0} cannot be referenced using its binary name +339 = Superinterface {0} is defined in an inherited type and an enclosing scope +340 = Duplicate field {0}.{1} +341 = Duplicate modifier for the field {0} +342 = Illegal modifier for the field {0}; only public, protected, private, static, final, transient & volatile are permitted +343 = Illegal modifier for the interface field {0}; only public, static & final are permitted +344 = The field {0} can only set one of public / protected / private +345 = The field {0} can be either final or volatile, not both +346 = The field {0} cannot be declared static; static fields can only be declared in static or top level types + +350 = {2} cannot be resolved (or is not a valid type) for the field {1}.{0} +351 = The type {2} is not visible for the field {1}.{0} +352 = The type {2} is ambiguous for the field {1}.{0} +353 = The field type {2} cannot be referenced using its binary name +354 = The field type {2} is defined in an inherited type and an enclosing scope +355 = Duplicate method {0} in type {1} +356 = Illegal modifier for parameter {0}; only final is permitted +357 = Duplicate modifier for the method {1} in type {0} +358 = Illegal modifier for the method {1} in type {0} +359 = Illegal modifier for the interface method {1} in type {0}; only public & abstract are permitted +360 = The method {1} in type {0} can only set one of public / protected / private +361 = The method {1} cannot be declared static; static methods can only be declared in a static or top level type +362 = The abstract method {1} in type {0} can only set a visibility modifier, one of public or protected +363 = The abstract method {1} in type {0} can only be defined by an abstract class +364 = void is an invalid type for the parameter {1} of the method {0} +365 = An array of void is an invalid type for the parameter {1} of the method {0} +366 = An array of void is an invalid return type for the method {0} +367 = The native method {1} cannot also be declared strictfp +368 = Duplicate modifier for parameter {0} + +370 = {2} cannot be resolved (or is not a valid type) for the parameter {1} of the method {0} +371 = The type {2} is not visible for the parameter {1} of the method {0} +372 = The type {2} is ambiguous for the parameter {1} of the method {0} +373 = The parameter type {2} cannot be referenced using its binary name +374 = The parameter type {2} is defined in an inherited type and an enclosing scope +375 = {1} cannot be resolved (or is not an exception type) for the method {0} +376 = The exception type {1} is not visible for the method {0} +377 = The exception type {1} is ambiguous for the method {0} +378 = The exception type {1} cannot be referenced using its binary name +379 = The exception type {1} is defined in an inherited type and an enclosing scope +380 = {1} cannot be resolved (or is not a valid return type) for the method {0} +381 = The return type {1} is not visible for the method {0} +382 = The return type {1} is ambiguous for the method {0} +383 = The return type {1} cannot be referenced using its binary name +384 = The return type {1} is defined in an inherited type and an enclosing scope +385 = The import {0} conflicts with a type defined in the same file +386 = The import {0} collides with another imported type +387 = Only a type can be imported. {0} resolves to a package +388 = The import {0} is never used +390 = The import {0} cannot be resolved +391 = The imported type {0} is not visible +392 = The imported type {0} is ambiguous +393 = The imported type {0} cannot be referenced using its binary name +394 = The imported type {0} is defined in an inherited type and an enclosing scope +395 = Duplicate modifier for the variable {0} +396 = Illegal modifier for the variable {0}; only final is permitted + +400 = Class must implement the inherited abstract method {0} +401 = Cannot override the final method from {0} +402 = Exception {0} is not compatible with throws clause in {1} +403 = Exception {0} in throws clause of {1} is not compatible with {2} +404 = The return type is incompatible with {0} +405 = The inherited method {0} cannot hide the public abstract method in {1} +406 = This instance method cannot override the static method from {0} +407 = This static method cannot hide the instance method from {0} +408 = The static method {0} conflicts with the abstract method in {1} +409 = Cannot reduce the visibility of the inherited method from {0} +410 = The method {0} does not override the inherited method from {1} since it is private to a different package. +411 = This class must implement the inherited abstract method {1}, but cannot override it since it is not visible from {0}. Either make the type abstract or make the inherited method visible. +412 = The method {0} overrides a deprecated method from {1} +413 = The return type is incompatible with {0}, thus this interface cannot be implemented +414 = Exception {0} is not compatible with throws clause in {1}, thus this interface cannot be implemented + +420 = Code snippet support cannot find the class {0} +421 = Code snippet support cannot find the method {0}.{1}({2}) +422 = super cannot be used in the code snippet code + +430 = Too many constants, the constant pool for {0} would exceed 65536 entries +431 = The type generates a string that requires more than 65535 bytes to encode in Utf8 format in the constant pool + +432 = Too many fields for type {0}. Maximum is 65535 +433 = Too many methods for type {0}. Maximum is 65535 + +440 = ''assert'' should not be used as an identifier, since it is a reserved keyword from source level 1.4 on + +450 = {0} {1} + +460 = Empty block should be documented + +470 = Unexpected tag +471 = Missing tag for parameter {0} +472 = Missing parameter name +473 = Duplicate tag for parameter +474 = Parameter {0} is not declared +475 = Missing tag for return type +476 = Duplicate tag for return type +477 = Missing tag for declared exception {0} +478 = Missing class name +479 = Invalid class name +480 = Duplicate tag for thrown exception +481 = Exception {0} is not declared +482 = Missing reference +483 = Invalid reference +484 = Invalid URL link format +485 = Invalid parameters declaration +486 = Missing comment for {0} declaration +487 = Invalid tag +488 = {0} cannot be resolved or is not a field +489 = The field {0} is not visible +490 = The field {0} is ambiguous +491 = The field {0}.{1} is deprecated +492 = The constructor {0}({1}) is undefined +493 = The constructor {0}({1}) is not visible +494 = The constructor {0}({1}) is ambiguous +495 = The constructor {0}({1}) is deprecated +496 = The method {1}({2}) is undefined for the type {0} +497 = The method {1}({2}) from the type {0} is not visible +498 = The method {1}({2}) is ambiguous for the type {0} +499 = The method {1}({2}) from the type {0} is deprecated +500 = Cannot invoke {1}({2}) on the primitive type {0} +501 = The method {1}({2}) in the type {0} is not applicable for the arguments ({3}) +502 = Cannot invoke {1}({2}) on the array type {0} +503 = {0} cannot be resolved or is not a type +504 = The type {0} is not visible +505 = The type {0} is ambiguous +506 = The type {0} is deprecated +507 = The nested type {0} cannot be referenced using its binary name +508 = The method {1} is defined in an inherited type and an enclosing scope +509 = The field {0} is defined in an inherited type and an enclosing scope +510 = The type {0} is defined in an inherited type and an enclosing scope +511 = {0} is an ambiguous method reference or is not a field +512 = Missing closing brace for inline tag +513 = Malformed reference (missing end space separator) +515 = Javadoc: diff --git a/src/java/org/eclipse/jdt/internal/compiler/util/CompoundNameVector.java b/src/java/org/eclipse/jdt/internal/compiler/util/CompoundNameVector.java new file mode 100644 index 0000000..66adf23 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/util/CompoundNameVector.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.util; + +import org.eclipse.jdt.core.compiler.CharOperation; + +public final class CompoundNameVector { + static int INITIAL_SIZE = 10; + + public int size; + int maxSize; + char[][][] elements; +public CompoundNameVector() { + maxSize = INITIAL_SIZE; + size = 0; + elements = new char[maxSize][][]; +} +public void add(char[][] newElement) { + if (size == maxSize) // knows that size starts <= maxSize + System.arraycopy(elements, 0, (elements = new char[maxSize *= 2][][]), 0, size); + elements[size++] = newElement; +} +public void addAll(char[][][] newElements) { + if (size + newElements.length >= maxSize) { + maxSize = size + newElements.length; // assume no more elements will be added + System.arraycopy(elements, 0, (elements = new char[maxSize][][]), 0, size); + } + System.arraycopy(newElements, 0, elements, size, newElements.length); + size += newElements.length; +} +public boolean contains(char[][] element) { + for (int i = size; --i >= 0;) + if (CharOperation.equals(element, elements[i])) + return true; + return false; +} +public char[][] elementAt(int index) { + return elements[index]; +} +public char[][] remove(char[][] element) { + // assumes only one occurrence of the element exists + for (int i = size; --i >= 0;) + if (element == elements[i]) { + // shift the remaining elements down one spot + System.arraycopy(elements, i + 1, elements, i, --size - i); + elements[size] = null; + return element; + } + return null; +} +public void removeAll() { + for (int i = size; --i >= 0;) + elements[i] = null; + size = 0; +} +public String toString() { + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < size; i++) { + buffer.append(CharOperation.toString(elements[i])).append("\n"); //$NON-NLS-1$ + } + return buffer.toString(); +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/util/HashtableOfInt.java b/src/java/org/eclipse/jdt/internal/compiler/util/HashtableOfInt.java new file mode 100644 index 0000000..6ea5078 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/util/HashtableOfInt.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.util; + + /** + * Hashtable for non-zero int keys. + */ + +public final class HashtableOfInt { + // to avoid using Enumerations, walk the individual tables skipping nulls + public int[] keyTable; + public Object[] valueTable; + + public int elementSize; // number of elements in the table + int threshold; +public HashtableOfInt() { + this(13); +} +public HashtableOfInt(int size) { + this.elementSize = 0; + this.threshold = size; // size represents the expected number of elements + int extraRoom = (int) (size * 1.75f); + if (this.threshold == extraRoom) + extraRoom++; + this.keyTable = new int[extraRoom]; + this.valueTable = new Object[extraRoom]; +} +public boolean containsKey(int key) { + int index = key % valueTable.length; + int currentKey; + while ((currentKey = keyTable[index]) != 0) { + if (currentKey == key) + return true; + index = (index + 1) % keyTable.length; + } + return false; +} +public Object get(int key) { + int index = key % valueTable.length; + int currentKey; + while ((currentKey = keyTable[index]) != 0) { + if (currentKey == key) return valueTable[index]; + index = (index + 1) % keyTable.length; + } + return null; +} +public Object put(int key, Object value) { + int index = key % valueTable.length; + int currentKey; + while ((currentKey = keyTable[index]) != 0) { + if (currentKey == key) return valueTable[index] = value; + index = (index + 1) % keyTable.length; + } + keyTable[index] = key; + valueTable[index] = value; + + // assumes the threshold is never equal to the size of the table + if (++elementSize > threshold) + rehash(); + return value; +} +private void rehash() { + HashtableOfInt newHashtable = new HashtableOfInt(elementSize * 2); // double the number of expected elements + int currentKey; + for (int i = keyTable.length; --i >= 0;) + if ((currentKey = keyTable[i]) != 0) + newHashtable.put(currentKey, valueTable[i]); + + this.keyTable = newHashtable.keyTable; + this.valueTable = newHashtable.valueTable; + this.threshold = newHashtable.threshold; +} +public int size() { + return elementSize; +} +public String toString() { + String s = ""; //$NON-NLS-1$ + Object object; + for (int i = 0, length = valueTable.length; i < length; i++) + if ((object = valueTable[i]) != null) + s += keyTable[i] + " -> " + object.toString() + "\n"; //$NON-NLS-2$ //$NON-NLS-1$ + return s; +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/util/HashtableOfIntValues.java b/src/java/org/eclipse/jdt/internal/compiler/util/HashtableOfIntValues.java new file mode 100644 index 0000000..7c42adb --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/util/HashtableOfIntValues.java @@ -0,0 +1,148 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.util; + +import org.eclipse.jdt.core.compiler.CharOperation; + +/** + * Hashtable of {char[] --> int} + */ +public final class HashtableOfIntValues implements Cloneable { + + public static final int NO_VALUE = Integer.MIN_VALUE; + + // to avoid using Enumerations, walk the individual tables skipping nulls + public char[] keyTable[]; + public int valueTable[]; + + public int elementSize; // number of elements in the table + int threshold; + + public HashtableOfIntValues() { + this(13); + } + + public HashtableOfIntValues(int size) { + + this.elementSize = 0; + this.threshold = size; // size represents the expected number of elements + int extraRoom = (int) (size * 1.75f); + if (this.threshold == extraRoom) + extraRoom++; + this.keyTable = new char[extraRoom][]; + this.valueTable = new int[extraRoom]; + } + + public Object clone() throws CloneNotSupportedException { + HashtableOfIntValues result = (HashtableOfIntValues) super.clone(); + result.elementSize = this.elementSize; + result.threshold = this.threshold; + + int length = this.keyTable.length; + result.keyTable = new char[length][]; + System.arraycopy(this.keyTable, 0, result.keyTable, 0, length); + + length = this.valueTable.length; + result.valueTable = new int[length]; + System.arraycopy(this.valueTable, 0, result.valueTable, 0, length); + return result; + } + + public boolean containsKey(char[] key) { + + int index = CharOperation.hashCode(key) % valueTable.length; + int keyLength = key.length; + char[] currentKey; + while ((currentKey = keyTable[index]) != null) { + if (currentKey.length == keyLength && CharOperation.equals(currentKey, key)) + return true; + index = (index + 1) % keyTable.length; + } + return false; + } + + public int get(char[] key) { + + int index = CharOperation.hashCode(key) % valueTable.length; + int keyLength = key.length; + char[] currentKey; + while ((currentKey = keyTable[index]) != null) { + if (currentKey.length == keyLength && CharOperation.equals(currentKey, key)) + return valueTable[index]; + index = (index + 1) % keyTable.length; + } + return NO_VALUE; + } + + public int put(char[] key, int value) { + + int index = CharOperation.hashCode(key) % valueTable.length; + int keyLength = key.length; + char[] currentKey; + while ((currentKey = keyTable[index]) != null) { + if (currentKey.length == keyLength && CharOperation.equals(currentKey, key)) + return valueTable[index] = value; + index = (index + 1) % keyTable.length; + } + keyTable[index] = key; + valueTable[index] = value; + + // assumes the threshold is never equal to the size of the table + if (++elementSize > threshold) + rehash(); + return value; + } + + public int removeKey(char[] key) { + + int index = CharOperation.hashCode(key) % valueTable.length; + int keyLength = key.length; + char[] currentKey; + while ((currentKey = keyTable[index]) != null) { + if (currentKey.length == keyLength && CharOperation.equals(currentKey, key)) { + int value = valueTable[index]; + elementSize--; + keyTable[index] = null; + valueTable[index] = NO_VALUE; + rehash(); + return value; + } + index = (index + 1) % keyTable.length; + } + return NO_VALUE; + } + + private void rehash() { + + HashtableOfIntValues newHashtable = new HashtableOfIntValues(elementSize * 2); // double the number of expected elements + char[] currentKey; + for (int i = keyTable.length; --i >= 0;) + if ((currentKey = keyTable[i]) != null) + newHashtable.put(currentKey, valueTable[i]); + + this.keyTable = newHashtable.keyTable; + this.valueTable = newHashtable.valueTable; + this.threshold = newHashtable.threshold; + } + + public int size() { + return elementSize; + } + + public String toString() { + String s = ""; //$NON-NLS-1$ + char[] key; + for (int i = 0, length = valueTable.length; i < length; i++) + if ((key = keyTable[i]) != null) + s += new String(key) + " -> " + valueTable[i] + "\n"; //$NON-NLS-2$ //$NON-NLS-1$ + return s; + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/util/HashtableOfLong.java b/src/java/org/eclipse/jdt/internal/compiler/util/HashtableOfLong.java new file mode 100644 index 0000000..7437a6d --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/util/HashtableOfLong.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.util; + + /** + * Hashtable for non-zero long keys. + */ + +public final class HashtableOfLong { + // to avoid using Enumerations, walk the individual tables skipping nulls + public long[] keyTable; + public Object[] valueTable; + + public int elementSize; // number of elements in the table + int threshold; +public HashtableOfLong() { + this(13); +} +public HashtableOfLong(int size) { + this.elementSize = 0; + this.threshold = size; // size represents the expected number of elements + int extraRoom = (int) (size * 1.75f); + if (this.threshold == extraRoom) + extraRoom++; + this.keyTable = new long[extraRoom]; + this.valueTable = new Object[extraRoom]; +} +public boolean containsKey(long key) { + int index = ((int)(key >>> 32)) % valueTable.length; + long currentKey; + while ((currentKey = keyTable[index]) != 0) { + if (currentKey == key) + return true; + index = (index + 1) % keyTable.length; + } + return false; +} +public Object get(long key) { + int index = ((int)(key >>> 32)) % valueTable.length; + long currentKey; + while ((currentKey = keyTable[index]) != 0) { + if (currentKey == key) return valueTable[index]; + index = (index + 1) % keyTable.length; + } + return null; +} +public Object put(long key, Object value) { + int index = ((int)(key >>> 32)) % valueTable.length; + long currentKey; + while ((currentKey = keyTable[index]) != 0) { + if (currentKey == key) return valueTable[index] = value; + index = (index + 1) % keyTable.length; + } + keyTable[index] = key; + valueTable[index] = value; + + // assumes the threshold is never equal to the size of the table + if (++elementSize > threshold) + rehash(); + return value; +} +private void rehash() { + HashtableOfLong newHashtable = new HashtableOfLong(elementSize * 2); // double the number of expected elements + long currentKey; + for (int i = keyTable.length; --i >= 0;) + if ((currentKey = keyTable[i]) != 0) + newHashtable.put(currentKey, valueTable[i]); + + this.keyTable = newHashtable.keyTable; + this.valueTable = newHashtable.valueTable; + this.threshold = newHashtable.threshold; +} +public int size() { + return elementSize; +} +public String toString() { + String s = ""; //$NON-NLS-1$ + Object object; + for (int i = 0, length = valueTable.length; i < length; i++) + if ((object = valueTable[i]) != null) + s += keyTable[i] + " -> " + object.toString() + "\n"; //$NON-NLS-2$ //$NON-NLS-1$ + return s; +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/util/HashtableOfObject.java b/src/java/org/eclipse/jdt/internal/compiler/util/HashtableOfObject.java new file mode 100644 index 0000000..1acef0a --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/util/HashtableOfObject.java @@ -0,0 +1,146 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.util; + +import org.eclipse.jdt.core.compiler.CharOperation; + +/** + * Hashtable of {char[] --> Object } + */ +public final class HashtableOfObject implements Cloneable { + + // to avoid using Enumerations, walk the individual tables skipping nulls + public char[] keyTable[]; + public Object valueTable[]; + + public int elementSize; // number of elements in the table + int threshold; + + public HashtableOfObject() { + this(13); + } + + public HashtableOfObject(int size) { + + this.elementSize = 0; + this.threshold = size; // size represents the expected number of elements + int extraRoom = (int) (size * 1.75f); + if (this.threshold == extraRoom) + extraRoom++; + this.keyTable = new char[extraRoom][]; + this.valueTable = new Object[extraRoom]; + } + + public Object clone() throws CloneNotSupportedException { + HashtableOfObject result = (HashtableOfObject) super.clone(); + result.elementSize = this.elementSize; + result.threshold = this.threshold; + + int length = this.keyTable.length; + result.keyTable = new char[length][]; + System.arraycopy(this.keyTable, 0, result.keyTable, 0, length); + + length = this.valueTable.length; + result.valueTable = new Object[length]; + System.arraycopy(this.valueTable, 0, result.valueTable, 0, length); + return result; + } + + public boolean containsKey(char[] key) { + + int index = CharOperation.hashCode(key) % valueTable.length; + int keyLength = key.length; + char[] currentKey; + while ((currentKey = keyTable[index]) != null) { + if (currentKey.length == keyLength && CharOperation.equals(currentKey, key)) + return true; + index = (index + 1) % keyTable.length; + } + return false; + } + + public Object get(char[] key) { + + int index = CharOperation.hashCode(key) % valueTable.length; + int keyLength = key.length; + char[] currentKey; + while ((currentKey = keyTable[index]) != null) { + if (currentKey.length == keyLength && CharOperation.equals(currentKey, key)) + return valueTable[index]; + index = (index + 1) % keyTable.length; + } + return null; + } + + public Object put(char[] key, Object value) { + + int index = CharOperation.hashCode(key) % valueTable.length; + int keyLength = key.length; + char[] currentKey; + while ((currentKey = keyTable[index]) != null) { + if (currentKey.length == keyLength && CharOperation.equals(currentKey, key)) + return valueTable[index] = value; + index = (index + 1) % keyTable.length; + } + keyTable[index] = key; + valueTable[index] = value; + + // assumes the threshold is never equal to the size of the table + if (++elementSize > threshold) + rehash(); + return value; + } + + public Object removeKey(char[] key) { + + int index = CharOperation.hashCode(key) % valueTable.length; + int keyLength = key.length; + char[] currentKey; + while ((currentKey = keyTable[index]) != null) { + if (currentKey.length == keyLength && CharOperation.equals(currentKey, key)) { + Object value = valueTable[index]; + elementSize--; + keyTable[index] = null; + valueTable[index] = null; + rehash(); + return value; + } + index = (index + 1) % keyTable.length; + } + return null; + } + + private void rehash() { + + HashtableOfObject newHashtable = new HashtableOfObject(elementSize * 2); // double the number of expected elements + char[] currentKey; + for (int i = keyTable.length; --i >= 0;) + if ((currentKey = keyTable[i]) != null) + newHashtable.put(currentKey, valueTable[i]); + + this.keyTable = newHashtable.keyTable; + this.valueTable = newHashtable.valueTable; + this.threshold = newHashtable.threshold; + } + + public int size() { + return elementSize; + } + + public String toString() { + String s = ""; //$NON-NLS-1$ + Object object; + for (int i = 0, length = valueTable.length; i < length; i++) + if ((object = valueTable[i]) != null) + s += new String(keyTable[i]) + " -> " + object.toString() + "\n"; //$NON-NLS-2$ //$NON-NLS-1$ + return s; + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/util/HashtableOfPackage.java b/src/java/org/eclipse/jdt/internal/compiler/util/HashtableOfPackage.java new file mode 100644 index 0000000..3fd642a --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/util/HashtableOfPackage.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.util; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.lookup.PackageBinding; + +public final class HashtableOfPackage { + // to avoid using Enumerations, walk the individual tables skipping nulls + public char[] keyTable[]; + public PackageBinding valueTable[]; + + public int elementSize; // number of elements in the table + int threshold; +public HashtableOfPackage() { + this(3); // usually not very large +} +public HashtableOfPackage(int size) { + this.elementSize = 0; + this.threshold = size; // size represents the expected number of elements + int extraRoom = (int) (size * 1.75f); + if (this.threshold == extraRoom) + extraRoom++; + this.keyTable = new char[extraRoom][]; + this.valueTable = new PackageBinding[extraRoom]; +} +public boolean containsKey(char[] key) { + int index = CharOperation.hashCode(key) % valueTable.length; + int keyLength = key.length; + char[] currentKey; + while ((currentKey = keyTable[index]) != null) { + if (currentKey.length == keyLength && CharOperation.equals(currentKey, key)) + return true; + index = (index + 1) % keyTable.length; + } + return false; +} +public PackageBinding get(char[] key) { + int index = CharOperation.hashCode(key) % valueTable.length; + int keyLength = key.length; + char[] currentKey; + while ((currentKey = keyTable[index]) != null) { + if (currentKey.length == keyLength && CharOperation.equals(currentKey, key)) + return valueTable[index]; + index = (index + 1) % keyTable.length; + } + return null; +} +public PackageBinding put(char[] key, PackageBinding value) { + int index = CharOperation.hashCode(key) % valueTable.length; + int keyLength = key.length; + char[] currentKey; + while ((currentKey = keyTable[index]) != null) { + if (currentKey.length == keyLength && CharOperation.equals(currentKey, key)) + return valueTable[index] = value; + index = (index + 1) % keyTable.length; + } + keyTable[index] = key; + valueTable[index] = value; + + // assumes the threshold is never equal to the size of the table + if (++elementSize > threshold) + rehash(); + return value; +} +private void rehash() { + HashtableOfPackage newHashtable = new HashtableOfPackage(elementSize * 2); // double the number of expected elements + char[] currentKey; + for (int i = keyTable.length; --i >= 0;) + if ((currentKey = keyTable[i]) != null) + newHashtable.put(currentKey, valueTable[i]); + + this.keyTable = newHashtable.keyTable; + this.valueTable = newHashtable.valueTable; + this.threshold = newHashtable.threshold; +} +public int size() { + return elementSize; +} +public String toString() { + String s = ""; //$NON-NLS-1$ + PackageBinding pkg; + for (int i = 0, length = valueTable.length; i < length; i++) + if ((pkg = valueTable[i]) != null) + s += pkg.toString() + "\n"; //$NON-NLS-1$ + return s; +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/util/HashtableOfType.java b/src/java/org/eclipse/jdt/internal/compiler/util/HashtableOfType.java new file mode 100644 index 0000000..a64e8ea --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/util/HashtableOfType.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.util; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; + +public final class HashtableOfType { + // to avoid using Enumerations, walk the individual tables skipping nulls + public char[] keyTable[]; + public ReferenceBinding valueTable[]; + + public int elementSize; // number of elements in the table + int threshold; +public HashtableOfType() { + this(3); +} +public HashtableOfType(int size) { + this.elementSize = 0; + this.threshold = size; // size represents the expected number of elements + int extraRoom = (int) (size * 1.75f); + if (this.threshold == extraRoom) + extraRoom++; + this.keyTable = new char[extraRoom][]; + this.valueTable = new ReferenceBinding[extraRoom]; +} +public boolean containsKey(char[] key) { + int index = CharOperation.hashCode(key) % valueTable.length; + int keyLength = key.length; + char[] currentKey; + while ((currentKey = keyTable[index]) != null) { + if (currentKey.length == keyLength && CharOperation.equals(currentKey, key)) + return true; + index = (index + 1) % keyTable.length; + } + return false; +} +public ReferenceBinding get(char[] key) { + int index = CharOperation.hashCode(key) % valueTable.length; + int keyLength = key.length; + char[] currentKey; + while ((currentKey = keyTable[index]) != null) { + if (currentKey.length == keyLength && CharOperation.equals(currentKey, key)) + return valueTable[index]; + index = (index + 1) % keyTable.length; + } + return null; +} +public ReferenceBinding put(char[] key, ReferenceBinding value) { + int index = CharOperation.hashCode(key) % valueTable.length; + int keyLength = key.length; + char[] currentKey; + while ((currentKey = keyTable[index]) != null) { + if (currentKey.length == keyLength && CharOperation.equals(currentKey, key)) + return valueTable[index] = value; + index = (index + 1) % keyTable.length; + } + keyTable[index] = key; + valueTable[index] = value; + + // assumes the threshold is never equal to the size of the table + if (++elementSize > threshold) + rehash(); + return value; +} +private void rehash() { + HashtableOfType newHashtable = new HashtableOfType(elementSize < 100 ? 100 : elementSize * 2); // double the number of expected elements + char[] currentKey; + for (int i = keyTable.length; --i >= 0;) + if ((currentKey = keyTable[i]) != null) + newHashtable.put(currentKey, valueTable[i]); + + this.keyTable = newHashtable.keyTable; + this.valueTable = newHashtable.valueTable; + this.threshold = newHashtable.threshold; +} +public int size() { + return elementSize; +} +public String toString() { + String s = ""; //$NON-NLS-1$ + ReferenceBinding type; + for (int i = 0, length = valueTable.length; i < length; i++) + if ((type = valueTable[i]) != null) + s += type.toString() + "\n"; //$NON-NLS-1$ + return s; +} +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/util/ObjectVector.java b/src/java/org/eclipse/jdt/internal/compiler/util/ObjectVector.java new file mode 100644 index 0000000..50c93b0 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/util/ObjectVector.java @@ -0,0 +1,132 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.util; + +public final class ObjectVector { + + static int INITIAL_SIZE = 10; + + public int size; + int maxSize; + Object[] elements; + + public ObjectVector() { + + this.maxSize = INITIAL_SIZE; + this.size = 0; + this.elements = new Object[this.maxSize]; + } + + public void add(Object newElement) { + + if (this.size == this.maxSize) // knows that size starts <= maxSize + System.arraycopy(this.elements, 0, (this.elements = new Object[this.maxSize *= 2]), 0, this.size); + this.elements[this.size++] = newElement; + } + + public void addAll(Object[] newElements) { + + if (this.size + newElements.length >= this.maxSize) { + maxSize = this.size + newElements.length; // assume no more elements will be added + System.arraycopy(this.elements, 0, (this.elements = new Object[this.maxSize]), 0, this.size); + } + System.arraycopy(newElements, 0, this.elements, size, newElements.length); + this.size += newElements.length; + } + + public void addAll(ObjectVector newVector) { + + if (this.size + newVector.size >= this.maxSize) { + maxSize = this.size + newVector.size; // assume no more elements will be added + System.arraycopy(this.elements, 0, (this.elements = new Object[this.maxSize]), 0, this.size); + } + System.arraycopy(newVector.elements, 0, this.elements, size, newVector.size); + this.size += newVector.size; + } + + /** + * Identity check + */ + public boolean containsIdentical(Object element) { + + for (int i = this.size; --i >= 0;) + if (element == this.elements[i]) + return true; + return false; + } + + /** + * Equality check + */ + public boolean contains(Object element) { + + for (int i = this.size; --i >= 0;) + if (element.equals(this.elements[i])) + return true; + return false; + } + + public void copyInto(Object[] targetArray){ + + this.copyInto(targetArray, 0); + } + + public void copyInto(Object[] targetArray, int index){ + + System.arraycopy(this.elements, 0, targetArray, index, this.size); + } + + public Object elementAt(int index) { + + return this.elements[index]; + } + + public Object find(Object element) { + + for (int i = this.size; --i >= 0;) + if (element.equals(this.elements[i])) + return element; + return null; + } + + public Object remove(Object element) { + + // assumes only one occurrence of the element exists + for (int i = this.size; --i >= 0;) + if (element.equals(this.elements[i])) { + // shift the remaining elements down one spot + System.arraycopy(this.elements, i + 1, this.elements, i, --this.size - i); + this.elements[this.size] = null; + return element; + } + return null; + } + + public void removeAll() { + + for (int i = this.size; --i >= 0;) + this.elements[i] = null; + this.size = 0; + } + + public int size(){ + + return this.size; + } + + public String toString() { + + String s = ""; //$NON-NLS-1$ + for (int i = 0; i < this.size; i++) + s += this.elements[i].toString() + "\n"; //$NON-NLS-1$ + return s; + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/util/SimpleNameVector.java b/src/java/org/eclipse/jdt/internal/compiler/util/SimpleNameVector.java new file mode 100644 index 0000000..0c5b80b --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/util/SimpleNameVector.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.util; + +import org.eclipse.jdt.core.compiler.CharOperation; + +public final class SimpleNameVector { + + static int INITIAL_SIZE = 10; + + public int size; + int maxSize; + char[][] elements; + + public SimpleNameVector() { + + this.maxSize = INITIAL_SIZE; + this.size = 0; + this.elements = new char[this.maxSize][]; + } + + public void add(char[] newElement) { + + if (this.size == this.maxSize) // knows that size starts <= maxSize + System.arraycopy(this.elements, 0, (this.elements = new char[this.maxSize *= 2][]), 0, this.size); + this.elements[size++] = newElement; + } + + public void addAll(char[][] newElements) { + + if (this.size + newElements.length >= this.maxSize) { + this.maxSize = this.size + newElements.length; // assume no more elements will be added + System.arraycopy(this.elements, 0, (this.elements = new char[this.maxSize][]), 0, this.size); + } + System.arraycopy(newElements, 0, this.elements, this.size, newElements.length); + this.size += newElements.length; + } + + public void copyInto(Object[] targetArray){ + + System.arraycopy(this.elements, 0, targetArray, 0, this.size); + } + + public boolean contains(char[] element) { + + for (int i = this.size; --i >= 0;) + if (CharOperation.equals(element, this.elements[i])) + return true; + return false; + } + + public char[] elementAt(int index) { + return this.elements[index]; + } + + public char[] remove(char[] element) { + + // assumes only one occurrence of the element exists + for (int i = this.size; --i >= 0;) + if (element == this.elements[i]) { + // shift the remaining elements down one spot + System.arraycopy(this.elements, i + 1, this.elements, i, --this.size - i); + this.elements[this.size] = null; + return element; + } + return null; + } + + public void removeAll() { + + for (int i = this.size; --i >= 0;) + this.elements[i] = null; + this.size = 0; + } + + public int size(){ + + return this.size; + } + + public String toString() { + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < this.size; i++) { + buffer.append(this.elements[i]).append("\n"); //$NON-NLS-1$ + } + return buffer.toString(); + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/util/SuffixConstants.java b/src/java/org/eclipse/jdt/internal/compiler/util/SuffixConstants.java new file mode 100644 index 0000000..609cffb --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/util/SuffixConstants.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.util; + +public interface SuffixConstants { + public final static String EXTENSION_class = "class"; //$NON-NLS-1$ + public final static String EXTENSION_CLASS = "CLASS"; //$NON-NLS-1$ + public final static String EXTENSION_java = "java"; //$NON-NLS-1$ + public final static String EXTENSION_JAVA = "JAVA"; //$NON-NLS-1$ + + public final static String SUFFIX_STRING_class = "." + EXTENSION_class; //$NON-NLS-1$ + public final static String SUFFIX_STRING_CLASS = "." + EXTENSION_CLASS; //$NON-NLS-1$ + public final static String SUFFIX_STRING_java = "." + EXTENSION_java; //$NON-NLS-1$ + public final static String SUFFIX_STRING_JAVA = "." + EXTENSION_JAVA; //$NON-NLS-1$ + + public final static char[] SUFFIX_class = SUFFIX_STRING_class.toCharArray(); + public final static char[] SUFFIX_CLASS = SUFFIX_STRING_CLASS.toCharArray(); + public final static char[] SUFFIX_java = SUFFIX_STRING_java.toCharArray(); + public final static char[] SUFFIX_JAVA = SUFFIX_STRING_JAVA.toCharArray(); + + public final static String EXTENSION_jar = "jar"; //$NON-NLS-1$ + public final static String EXTENSION_JAR = "JAR"; //$NON-NLS-1$ + public final static String EXTENSION_zip = "zip"; //$NON-NLS-1$ + public final static String EXTENSION_ZIP = "ZIP"; //$NON-NLS-1$ + + public final static String SUFFIX_STRING_jar = "." + EXTENSION_jar; //$NON-NLS-1$ + public final static String SUFFIX_STRING_JAR = "." + EXTENSION_JAR; //$NON-NLS-1$ + public final static String SUFFIX_STRING_zip = "." + EXTENSION_zip; //$NON-NLS-1$ + public final static String SUFFIX_STRING_ZIP = "." + EXTENSION_ZIP; //$NON-NLS-1$ + + public final static char[] SUFFIX_jar = SUFFIX_STRING_jar.toCharArray(); + public final static char[] SUFFIX_JAR = SUFFIX_STRING_JAR.toCharArray(); + public final static char[] SUFFIX_zip = SUFFIX_STRING_zip.toCharArray(); + public final static char[] SUFFIX_ZIP = SUFFIX_STRING_ZIP.toCharArray(); +} \ No newline at end of file diff --git a/src/java/org/eclipse/jdt/internal/compiler/util/Util.java b/src/java/org/eclipse/jdt/internal/compiler/util/Util.java new file mode 100644 index 0000000..94b7567 --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/util/Util.java @@ -0,0 +1,523 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.util; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import org.eclipse.jdt.core.compiler.CharOperation; + +public class Util implements SuffixConstants { + + public interface Displayable { + String displayString(Object o); + } + + public static String LINE_SEPARATOR = System.getProperty("line.separator"); //$NON-NLS-1$ + public static char[] LINE_SEPARATOR_CHARS = LINE_SEPARATOR.toCharArray(); + + private final static char[] DOUBLE_QUOTES = "''".toCharArray(); //$NON-NLS-1$ + private final static char[] SINGLE_QUOTE = "'".toCharArray(); //$NON-NLS-1$ + private static final int DEFAULT_READING_SIZE = 8192; + + /* Bundle containing messages */ + protected static ResourceBundle bundle; + private final static String bundleName = + "org.eclipse.jdt.internal.compiler.util.messages"; //$NON-NLS-1$ + static { + relocalize(); + } + /** + * Lookup the message with the given ID in this catalog and bind its + * substitution locations with the given strings. + */ + public static String bind(String id, String binding1, String binding2) { + return bind(id, new String[] { binding1, binding2 }); + } + /** + * Lookup the message with the given ID in this catalog and bind its + * substitution locations with the given string. + */ + public static String bind(String id, String binding) { + return bind(id, new String[] { binding }); + } + /** + * Lookup the message with the given ID in this catalog and bind its + * substitution locations with the given string values. + */ + public static String bind(String id, String[] bindings) { + if (id == null) + return "No message available"; //$NON-NLS-1$ + String message = null; + try { + message = bundle.getString(id); + } catch (MissingResourceException e) { + // If we got an exception looking for the message, fail gracefully by just returning + // the id we were looking for. In most cases this is semi-informative so is not too bad. + return "Missing message: " + id + " in: " + bundleName; //$NON-NLS-2$ //$NON-NLS-1$ + } + // for compatibility with MessageFormat which eliminates double quotes in original message + char[] messageWithNoDoubleQuotes = + CharOperation.replace(message.toCharArray(), DOUBLE_QUOTES, SINGLE_QUOTE); + + if (bindings == null) return new String(messageWithNoDoubleQuotes); + + int length = messageWithNoDoubleQuotes.length; + int start = 0; + int end = length; + StringBuffer output = null; + while (true) { + if ((end = CharOperation.indexOf('{', messageWithNoDoubleQuotes, start)) > -1) { + if (output == null) output = new StringBuffer(length+bindings.length*20); + output.append(messageWithNoDoubleQuotes, start, end - start); + if ((start = CharOperation.indexOf('}', messageWithNoDoubleQuotes, end + 1)) > -1) { + int index = -1; + String argId = new String(messageWithNoDoubleQuotes, end + 1, start - end - 1); + try { + index = Integer.parseInt(argId); + output.append(bindings[index]); + } catch (NumberFormatException nfe) { // could be nested message ID {compiler.name} + boolean done = false; + if (!id.equals(argId)) { + String argMessage = null; + try { + argMessage = bundle.getString(argId); + output.append(argMessage); + done = true; + } catch (MissingResourceException e) { + // unable to bind argument, ignore (will leave argument in) + } + } + if (!done) output.append(messageWithNoDoubleQuotes, end + 1, start - end); + } catch (ArrayIndexOutOfBoundsException e) { + output.append("{missing " + Integer.toString(index) + "}"); //$NON-NLS-2$ //$NON-NLS-1$ + } + start++; + } else { + output.append(messageWithNoDoubleQuotes, end, length); + break; + } + } else { + if (output == null) return new String(messageWithNoDoubleQuotes); + output.append(messageWithNoDoubleQuotes, start, length - start); + break; + } + } + return output.toString(); + } + /** + * Lookup the message with the given ID in this catalog + */ + public static String bind(String id) { + return bind(id, (String[]) null); + } + /** + * Creates a NLS catalog for the given locale. + */ + public static void relocalize() { + try { + bundle = ResourceBundle.getBundle(bundleName, Locale.getDefault()); + } catch(MissingResourceException e) { + System.out.println("Missing resource : " + bundleName.replace('.', '/') + ".properties for locale " + Locale.getDefault()); //$NON-NLS-1$//$NON-NLS-2$ + throw e; + } + } + /** + * 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 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 BufferedInputStream(new FileInputStream(file)); + return getInputStreamAsCharArray(stream, (int) file.length(), encoding); + } finally { + if (stream != null) { + try { + stream.close(); + } catch (IOException e) { + // ignore + } + } + } + } + /* + * 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), only length chars + * are returned. Otherwise all chars in the stream are returned. + * 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 { + InputStreamReader reader = null; + reader = encoding == null + ? new InputStreamReader(stream) + : new InputStreamReader(stream, encoding); + char[] contents; + if (length == -1) { + contents = CharOperation.NO_CHAR; + 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 char[contentsLength + amountRequested], + 0, + contentsLength); + } + + // read as many chars as possible + amountRead = reader.read(contents, contentsLength, amountRequested); + + if (amountRead > 0) { + // remember length of contents + contentsLength += amountRead; + } + } while (amountRead != -1); + + // Do not keep first character for UTF-8 BOM encoding + int start = 0; + if (contentsLength > 0 && "UTF-8".equals(encoding)) { //$NON-NLS-1$ + if (contents[0] == 0xFEFF) { // if BOM char then skip + contentsLength--; + start = 1; + } + } + // resize contents if necessary + if (contentsLength < contents.length) { + System.arraycopy( + contents, + start, + contents = new char[contentsLength], + 0, + contentsLength); + } + } else { + contents = new char[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 = reader.read(contents, len, length - len); + } + // Do not keep first character for UTF-8 BOM encoding + int start = 0; + if (length > 0 && "UTF-8".equals(encoding)) { //$NON-NLS-1$ + if (contents[0] == 0xFEFF) { // if BOM char then skip + len--; + start = 1; + } + } + // See PR 1FMS89U + // Now we need to resize in case the default encoding used more than one byte for each + // character + if (len != length) + System.arraycopy(contents, start, (contents = new char[len]), 0, len); + } + + return contents; + } + + /** + * 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 { + stream = new BufferedInputStream(zip.getInputStream(ze)); + return getInputStreamAsByteArray(stream, (int) ze.getSize()); + } finally { + if (stream != null) { + try { + stream.close(); + } catch (IOException e) { + // ignore + } + } + } + } + /** + * Returns true iff str.toLowerCase().endsWith(".jar") || str.toLowerCase().endsWith(".zip") + * implementation is not creating extra strings. + */ + public final static boolean isArchiveFileName(String name) { + int nameLength = name == null ? 0 : name.length(); + int suffixLength = SUFFIX_JAR.length; + if (nameLength < suffixLength) return false; + + // try to match as JAR file + for (int i = 0; i < suffixLength; i++) { + char c = name.charAt(nameLength - i - 1); + int suffixIndex = suffixLength - i - 1; + if (c != SUFFIX_jar[suffixIndex] && c != SUFFIX_JAR[suffixIndex]) { + + // try to match as ZIP file + suffixLength = SUFFIX_ZIP.length; + if (nameLength < suffixLength) return false; + for (int j = 0; j < suffixLength; j++) { + c = name.charAt(nameLength - j - 1); + suffixIndex = suffixLength - j - 1; + if (c != SUFFIX_zip[suffixIndex] && c != SUFFIX_ZIP[suffixIndex]) return false; + } + return true; + } + } + 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; + } + /** + * 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(".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; + } + /** + * 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; + } + /** + * 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(); + } + + /** + * 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; + } + } +} diff --git a/src/java/org/eclipse/jdt/internal/compiler/util/messages.properties b/src/java/org/eclipse/jdt/internal/compiler/util/messages.properties new file mode 100644 index 0000000..8a1f05c --- /dev/null +++ b/src/java/org/eclipse/jdt/internal/compiler/util/messages.properties @@ -0,0 +1,69 @@ +############################################################################### +# Copyright (c) 2000, 2004 IBM Corporation and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Common Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/cpl-v10.html +# +# Contributors: +# IBM Corporation - initial API and implementation +############################################################################### +### Eclipse Java Core Compiler messages. + +### compilation +compilation.unresolvedProblem = Unresolved compilation problem: \n +compilation.unresolvedProblems = Unresolved compilation problems: \n +compilation.request = [parsing {2} - #{0}/{1}] +compilation.loadBinary = [reading {0}.class] +compilation.process = [analyzing {2} - #{0}/{1}] +compilation.write = [writing {1} - #{0}] +compilation.done = [completed {2} - #{0}/{1}] +compilation.units = [{0} units compiled] +compilation.unit = [{0} unit compiled] +compilation.internalError = Internal compiler error + +### output +output.isFile = The outDir is a file : {0} +output.isFileNotDirectory = The outDir is a file not a directory. +output.dirName = The output dir name is : {0} +output.notValidAll = The outDir is not a valid directory name. All the directories cannot be created. +output.fileName = file name : {0} +output.notValid = The outDir is not a valid directory name. The directory cannot be created. + +### problem +problem.noSourceInformation = \n!! no source information available !! +problem.atLine = (at line {0}) + +### abort +abort.invalidAttribute = SANITY CHECK: Invalid attribute for local variable {0} +abort.missingCode = Missing code implementation in the compiler +abort.againstSourceModel = Cannot compile against source model {0} issued from {1} + +### accept +accept.cannot = Cannot accept the compilation unit: + +### parser +parser.incorrectPath = The path for the javadcl.java file is incorrect +parser.moveFiles = MOVE FILES IN THE Runtime DIRECTORY OF Parser.class +parser.syntaxRecovery = SYNTAX RECOVERY +parser.regularParse = REGULAR PARSE +parser.missingFile = missing file {0} +parser.corruptedFile = corrupted file {0} +parser.endOfFile = end of file +parser.endOfConstructor = end of constructor +parser.endOfMethod = end of method +parser.endOfInitializer = end of initializer + +### binding +binding.subclass = anonymous subclass of {0} +binding.implementation = anonymous implementation of {0} + +### ast +ast.missingCode = Missing code gen implementation + +### constant +constant.cannotCastedInto = {0} constant cannot be casted into {1} +constant.cannotConvertedTo = {0} constant cannot be converted to {1} + +### miscellaneous +error.undefinedBaseType = Undefined base type: {0}