| /******************************************************************************* |
| * Copyright (c) 2000, 2003 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Common Public License v1.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.debug.eval.ast.instructions; |
| |
| |
| import org.eclipse.jdt.core.compiler.CharOperation; |
| |
| /** |
| * Copy of org.eclipse.jdt.core.Signature. The class is copied here |
| * solely for the purpose of commenting out the line: |
| * CharOperation.replace(result, C_DOLLAR, C_DOT); |
| * in the method toCharArray(char[]). |
| * See Bug 22165 |
| */ |
| public class RuntimeSignature { |
| public static final char C_BOOLEAN = 'Z'; |
| public static final char C_BYTE = 'B'; |
| public static final char C_CHAR = 'C'; |
| public static final char C_DOUBLE = 'D'; |
| public static final char C_FLOAT = 'F'; |
| public static final char C_INT = 'I'; |
| public static final char C_SEMICOLON = ';'; |
| public static final char C_LONG = 'J'; |
| public static final char C_SHORT = 'S'; |
| public static final char C_VOID = 'V'; |
| public static final char C_DOT = '.'; |
| public static final char C_DOLLAR = '$'; |
| public static final char C_ARRAY = '['; |
| public static final char C_RESOLVED = 'L'; |
| public static final char C_UNRESOLVED = 'Q'; |
| public static final char C_NAME_END = ';'; |
| public static final char C_PARAM_START = '('; |
| public static final char C_PARAM_END = ')'; |
| public static final String SIG_BOOLEAN = "Z"; //$NON-NLS-1$ |
| public static final String SIG_BYTE = "B"; //$NON-NLS-1$ |
| public static final String SIG_CHAR = "C"; //$NON-NLS-1$ |
| public static final String SIG_DOUBLE = "D"; //$NON-NLS-1$ |
| public static final String SIG_FLOAT = "F"; //$NON-NLS-1$ |
| public static final String SIG_INT = "I"; //$NON-NLS-1$ |
| public static final String SIG_LONG = "J"; //$NON-NLS-1$ |
| public static final String SIG_SHORT = "S"; //$NON-NLS-1$ |
| public static final String SIG_VOID = "V"; //$NON-NLS-1$ |
| private static final char[] NO_CHAR = new char[0]; |
| private static final char[] BOOLEAN = { 'b', 'o', 'o', 'l', 'e', 'a', 'n' }; |
| private static final char[] BYTE = { 'b', 'y', 't', 'e' }; |
| private static final char[] CHAR = { 'c', 'h', 'a', 'r' }; |
| private static final char[] DOUBLE = { 'd', 'o', 'u', 'b', 'l', 'e' }; |
| private static final char[] FLOAT = { 'f', 'l', 'o', 'a', 't' }; |
| private static final char[] INT = { 'i', 'n', 't' }; |
| private static final char[] LONG = { 'l', 'o', 'n', 'g' }; |
| private static final char[] SHORT = { 's', 'h', 'o', 'r', 't' }; |
| private static final char[] VOID = { 'v', 'o', 'i', 'd' }; |
| |
| public static String toString(String signature) |
| throws IllegalArgumentException { |
| return new String(toCharArray(signature.toCharArray())); |
| } |
| |
| public static char[] toCharArray(char[] signature) |
| throws IllegalArgumentException { |
| try { |
| int sigLength = signature.length; |
| |
| if (sigLength == 0 || signature[0] == C_PARAM_START) { |
| return toCharArray(signature, NO_CHAR, null, true, true); |
| } |
| |
| // compute result length |
| int resultLength = 0; |
| int index = -1; |
| while (signature[++index] == C_ARRAY) { |
| resultLength += 2; // [] |
| } |
| switch (signature[index]) { |
| case C_BOOLEAN : |
| resultLength += BOOLEAN.length; |
| break; |
| case C_BYTE : |
| resultLength += BYTE.length; |
| break; |
| case C_CHAR : |
| resultLength += CHAR.length; |
| break; |
| case C_DOUBLE : |
| resultLength += DOUBLE.length; |
| break; |
| case C_FLOAT : |
| resultLength += FLOAT.length; |
| break; |
| case C_INT : |
| resultLength += INT.length; |
| break; |
| case C_LONG : |
| resultLength += LONG.length; |
| break; |
| case C_SHORT : |
| resultLength += SHORT.length; |
| break; |
| case C_VOID : |
| resultLength += VOID.length; |
| break; |
| case C_RESOLVED : |
| case C_UNRESOLVED : |
| int end = |
| CharOperation.indexOf(C_SEMICOLON, signature, index); |
| if (end == -1) |
| throw new IllegalArgumentException(); |
| int start = index + 1; |
| resultLength += end - start; |
| break; |
| default : |
| throw new IllegalArgumentException(); |
| } |
| |
| char[] result = new char[resultLength]; |
| copyType(signature, 0, result, 0, true); |
| |
| /** |
| * Converts '$' separated type signatures into '.' separated type signature. |
| * NOTE: This assumes that the type signature is an inner type signature. |
| * This is true in most cases, but someone can define a non-inner type |
| * name containing a '$'. However to tell the difference, we would have |
| * to resolve the signature, which cannot be done at this point. |
| */ |
| // CharOperation.replace(result, C_DOLLAR, C_DOT); |
| |
| return result; |
| } catch (ArrayIndexOutOfBoundsException e) { |
| throw new IllegalArgumentException(); |
| } |
| } |
| |
| public static char[] toCharArray( |
| char[] methodSignature, |
| char[] methodName, |
| char[][] parameterNames, |
| boolean fullyQualifyTypeNames, |
| boolean includeReturnType) { |
| try { |
| int firstParen = |
| CharOperation.indexOf(C_PARAM_START, methodSignature); |
| if (firstParen == -1) |
| throw new IllegalArgumentException(); |
| |
| int sigLength = methodSignature.length; |
| |
| // compute result length |
| |
| // method signature |
| int paramCount = 0; |
| int lastParen = -1; |
| int resultLength = 0; |
| signature : for (int i = firstParen; i < sigLength; i++) { |
| switch (methodSignature[i]) { |
| case C_ARRAY : |
| resultLength += 2; // [] |
| continue signature; |
| case C_BOOLEAN : |
| resultLength += BOOLEAN.length; |
| break; |
| case C_BYTE : |
| resultLength += BYTE.length; |
| break; |
| case C_CHAR : |
| resultLength += CHAR.length; |
| break; |
| case C_DOUBLE : |
| resultLength += DOUBLE.length; |
| break; |
| case C_FLOAT : |
| resultLength += FLOAT.length; |
| break; |
| case C_INT : |
| resultLength += INT.length; |
| break; |
| case C_LONG : |
| resultLength += LONG.length; |
| break; |
| case C_SHORT : |
| resultLength += SHORT.length; |
| break; |
| case C_VOID : |
| resultLength += VOID.length; |
| break; |
| case C_RESOLVED : |
| case C_UNRESOLVED : |
| int end = |
| CharOperation.indexOf( |
| C_SEMICOLON, |
| methodSignature, |
| i); |
| if (end == -1) |
| throw new IllegalArgumentException(); |
| int start; |
| if (fullyQualifyTypeNames) { |
| start = i + 1; |
| } else { |
| start = |
| CharOperation.lastIndexOf( |
| C_DOT, |
| methodSignature, |
| i, |
| end) |
| + 1; |
| if (start == 0) |
| start = i + 1; |
| } |
| resultLength += end - start; |
| i = end; |
| break; |
| case C_PARAM_START : |
| // add space for "(" |
| resultLength++; |
| continue signature; |
| case C_PARAM_END : |
| lastParen = i; |
| if (includeReturnType) { |
| if (paramCount > 0) { |
| // remove space for ", " that was added with last parameter and remove space that is going to be added for ", " after return type |
| // and add space for ") " |
| resultLength -= 2; |
| } //else |
| // remove space that is going to be added for ", " after return type |
| // and add space for ") " |
| // -> noop |
| |
| // decrement param count because it is going to be added for return type |
| paramCount--; |
| continue signature; |
| } else { |
| if (paramCount > 0) { |
| // remove space for ", " that was added with last parameter and add space for ")" |
| resultLength--; |
| } else { |
| // add space for ")" |
| resultLength++; |
| } |
| break signature; |
| } |
| default : |
| throw new IllegalArgumentException(); |
| } |
| resultLength += 2; // add space for ", " |
| paramCount++; |
| } |
| |
| // parameter names |
| int parameterNamesLength = |
| parameterNames == null ? 0 : parameterNames.length; |
| for (int i = 0; i < parameterNamesLength; i++) { |
| resultLength += parameterNames[i].length + 1; |
| // parameter name + space |
| } |
| |
| // selector |
| int selectorLength = methodName == null ? 0 : methodName.length; |
| resultLength += selectorLength; |
| |
| // create resulting char array |
| char[] result = new char[resultLength]; |
| |
| // returned type |
| int index = 0; |
| if (includeReturnType) { |
| long pos = |
| copyType( |
| methodSignature, |
| lastParen + 1, |
| result, |
| index, |
| fullyQualifyTypeNames); |
| index = (int) (pos >>> 32); |
| result[index++] = ' '; |
| } |
| |
| // selector |
| if (methodName != null) { |
| System.arraycopy(methodName, 0, result, index, selectorLength); |
| index += selectorLength; |
| } |
| |
| // parameters |
| result[index++] = C_PARAM_START; |
| int sigPos = firstParen + 1; |
| for (int i = 0; i < paramCount; i++) { |
| long pos = |
| copyType( |
| methodSignature, |
| sigPos, |
| result, |
| index, |
| fullyQualifyTypeNames); |
| index = (int) (pos >>> 32); |
| sigPos = (int) pos; |
| if (parameterNames != null) { |
| result[index++] = ' '; |
| char[] parameterName = parameterNames[i]; |
| int paramLength = parameterName.length; |
| System.arraycopy( |
| parameterName, |
| 0, |
| result, |
| index, |
| paramLength); |
| index += paramLength; |
| } |
| if (i != paramCount - 1) { |
| result[index++] = ','; |
| result[index++] = ' '; |
| } |
| } |
| if (sigPos >= sigLength) { |
| throw new IllegalArgumentException(); |
| // should be on last paren |
| } |
| result[index++] = C_PARAM_END; |
| |
| return result; |
| } catch (ArrayIndexOutOfBoundsException e) { |
| throw new IllegalArgumentException(); |
| } |
| } |
| |
| private static long copyType( |
| char[] signature, |
| int sigPos, |
| char[] dest, |
| int index, |
| boolean fullyQualifyTypeNames) { |
| int arrayCount = 0; |
| loop : while (true) { |
| switch (signature[sigPos++]) { |
| case C_ARRAY : |
| arrayCount++; |
| break; |
| case C_BOOLEAN : |
| int length = BOOLEAN.length; |
| System.arraycopy(BOOLEAN, 0, dest, index, length); |
| index += length; |
| break loop; |
| case C_BYTE : |
| length = BYTE.length; |
| System.arraycopy(BYTE, 0, dest, index, length); |
| index += length; |
| break loop; |
| case C_CHAR : |
| length = CHAR.length; |
| System.arraycopy(CHAR, 0, dest, index, length); |
| index += length; |
| break loop; |
| case C_DOUBLE : |
| length = DOUBLE.length; |
| System.arraycopy(DOUBLE, 0, dest, index, length); |
| index += length; |
| break loop; |
| case C_FLOAT : |
| length = FLOAT.length; |
| System.arraycopy(FLOAT, 0, dest, index, length); |
| index += length; |
| break loop; |
| case C_INT : |
| length = INT.length; |
| System.arraycopy(INT, 0, dest, index, length); |
| index += length; |
| break loop; |
| case C_LONG : |
| length = LONG.length; |
| System.arraycopy(LONG, 0, dest, index, length); |
| index += length; |
| break loop; |
| case C_SHORT : |
| length = SHORT.length; |
| System.arraycopy(SHORT, 0, dest, index, length); |
| index += length; |
| break loop; |
| case C_VOID : |
| length = VOID.length; |
| System.arraycopy(VOID, 0, dest, index, length); |
| index += length; |
| break loop; |
| case C_RESOLVED : |
| case C_UNRESOLVED : |
| int end = |
| CharOperation.indexOf(C_SEMICOLON, signature, sigPos); |
| if (end == -1) |
| throw new IllegalArgumentException(); |
| int start; |
| if (fullyQualifyTypeNames) { |
| start = sigPos; |
| } else { |
| start = |
| CharOperation.lastIndexOf( |
| C_DOT, |
| signature, |
| sigPos, |
| end) |
| + 1; |
| if (start == 0) |
| start = sigPos; |
| } |
| length = end - start; |
| System.arraycopy(signature, start, dest, index, length); |
| sigPos = end + 1; |
| index += length; |
| break loop; |
| } |
| } |
| while (arrayCount-- > 0) { |
| dest[index++] = '['; |
| dest[index++] = ']'; |
| } |
| return (((long) index) << 32) + sigPos; |
| } |
| } |