| /******************************************************************************* |
| * Copyright (c) 2000, 2015 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jdi.internal; |
| |
| import com.sun.jdi.ClassLoaderReference; |
| import com.sun.jdi.ClassNotLoadedException; |
| import com.sun.jdi.ClassNotPreparedException; |
| import com.sun.jdi.Type; |
| import com.sun.jdi.Value; |
| |
| /** |
| * this class implements the corresponding interfaces declared by the JDI |
| * specification. See the com.sun.jdi package for more information. |
| * |
| */ |
| public abstract class TypeImpl extends AccessibleImpl implements Type { |
| /** Text representation of this type. */ |
| protected String fName = null; |
| /** JNI-style signature for this type. */ |
| protected String fSignature = null; |
| |
| /** |
| * Creates new instance, used for REFERENCE types. |
| */ |
| protected TypeImpl(String description, VirtualMachineImpl vmImpl) { |
| super(description, vmImpl); |
| } |
| |
| /** |
| * Creates new instance, used for PRIMITIVE types or VOID. |
| */ |
| protected TypeImpl(String description, VirtualMachineImpl vmImpl, |
| String name, String signature) { |
| super(description, vmImpl); |
| setName(name); |
| setSignature(signature); |
| } |
| |
| /** |
| * @return Returns new instance based on signature and (if it is a |
| * ReferenceType) classLoader. |
| * @throws ClassNotLoadedException |
| * when type is a ReferenceType and it has not been loaded by |
| * the specified class loader. |
| */ |
| public static TypeImpl create(VirtualMachineImpl vmImpl, String signature, |
| ClassLoaderReference classLoader) throws ClassNotLoadedException { |
| // For void values, a VoidType is always returned. |
| if (isVoidSignature(signature)) |
| return new VoidTypeImpl(vmImpl); |
| |
| // For primitive variables, an appropriate PrimitiveType is always |
| // returned. |
| if (isPrimitiveSignature(signature)) |
| return PrimitiveTypeImpl.create(vmImpl, signature); |
| |
| // For object variables, the appropriate ReferenceType is returned if it |
| // has |
| // been loaded through the enclosing type's class loader. |
| return ReferenceTypeImpl.create(vmImpl, signature, classLoader); |
| } |
| |
| /** |
| * Assigns name. |
| */ |
| public void setName(String name) { |
| fName = name; |
| } |
| |
| /** |
| * Assigns signature. |
| */ |
| public void setSignature(String signature) { |
| fSignature = signature; |
| } |
| |
| /** |
| * @return Returns description of Mirror object. |
| */ |
| @Override |
| public String toString() { |
| try { |
| return name(); |
| } catch (ClassNotPreparedException e) { |
| return JDIMessages.TypeImpl__Unloaded_Type__1; |
| } catch (Exception e) { |
| return fDescription; |
| } |
| } |
| |
| /** |
| * @return Create a null value instance of the type. |
| */ |
| public abstract Value createNullValue(); |
| |
| /** |
| * @return Returns text representation of this type. |
| */ |
| @Override |
| public String name() { |
| return fName; |
| } |
| |
| /** |
| * @return JNI-style signature for this type. |
| */ |
| @Override |
| public String signature() { |
| return fSignature; |
| } |
| |
| /** |
| * @return Returns modifier bits. |
| */ |
| @Override |
| public abstract int modifiers(); |
| |
| /** |
| * Converts a class name to a JNI signature. |
| */ |
| public static String classNameToSignature(String qualifiedName) { |
| // L<classname>; : fully-qualified-class |
| /* |
| * JNI signature examples: int[][] -> [[I long[] -> [J java.lang.String |
| * -> Ljava/lang/String; java.lang.String[] -> [Ljava/lang/String; |
| */ |
| StringBuilder signature = new StringBuilder(); |
| |
| int firstBrace = qualifiedName.indexOf('['); |
| if (firstBrace < 0) { |
| // Not an array type. Must be class type. |
| signature.append('L'); |
| signature.append(qualifiedName.replace('.', '/')); |
| signature.append(';'); |
| return signature.toString(); |
| } |
| |
| int index = 0; |
| while ((index = (qualifiedName.indexOf('[', index) + 1)) > 0) { |
| signature.append('['); |
| } |
| |
| String name = qualifiedName.substring(0, firstBrace); |
| switch (name.charAt(0)) { |
| // Check for primitive array type |
| case 'b': |
| if (name.equals("byte")) { //$NON-NLS-1$ |
| signature.append('B'); |
| return signature.toString(); |
| } else if (name.equals("boolean")) { //$NON-NLS-1$ |
| signature.append('Z'); |
| return signature.toString(); |
| } |
| break; |
| case 'i': |
| if (name.equals("int")) { //$NON-NLS-1$ |
| signature.append('I'); |
| return signature.toString(); |
| } |
| break; |
| case 'd': |
| if (name.equals("double")) { //$NON-NLS-1$ |
| signature.append('D'); |
| return signature.toString(); |
| } |
| break; |
| case 's': |
| if (name.equals("short")) { //$NON-NLS-1$ |
| signature.append('S'); |
| return signature.toString(); |
| } |
| break; |
| case 'c': |
| if (name.equals("char")) { //$NON-NLS-1$ |
| signature.append('C'); |
| return signature.toString(); |
| } |
| break; |
| case 'l': |
| if (name.equals("long")) { //$NON-NLS-1$ |
| signature.append('J'); |
| return signature.toString(); |
| } |
| break; |
| case 'f': |
| if (name.equals("float")) { //$NON-NLS-1$ |
| signature.append('F'); |
| return signature.toString(); |
| } |
| break; |
| } |
| // Class type array |
| signature.append('L'); |
| signature.append(name.replace('.', '/')); |
| signature.append(';'); |
| return signature.toString(); |
| } |
| |
| /** |
| * Converts a JNI class signature to a name. |
| */ |
| public static String classSignatureToName(String signature) { |
| // L<classname>; : fully-qualified-class |
| return signature.substring(1, signature.length() - 1).replace('/', '.'); |
| } |
| |
| /** |
| * Converts a JNI array signature to a name. |
| */ |
| public static String arraySignatureToName(String signature) { |
| // [<type> : array of type <type> |
| if (signature.indexOf('[') < 0) { |
| return signature; |
| } |
| StringBuilder name = new StringBuilder(); |
| String type = signature.substring(signature.lastIndexOf('[') + 1); |
| if (type.length() == 1 && isPrimitiveSignature(type)) { |
| name.append(getPrimitiveSignatureToName(type.charAt(0))); |
| } else { |
| name.append(classSignatureToName(type)); |
| } |
| int index = 0; |
| while ((index = (signature.indexOf('[', index) + 1)) > 0) { |
| name.append('[').append(']'); |
| } |
| return signatureToName(signature.substring(1)) + "[]"; //$NON-NLS-1$ |
| } |
| |
| /** |
| * @returns Returns Type Name, converted from a JNI signature. |
| */ |
| public static String signatureToName(String signature) { |
| // See JNI 1.1 Specification, Table 3-2 Java VM Type Signatures. |
| String primitive = getPrimitiveSignatureToName(signature.charAt(0)); |
| if (primitive != null) { |
| return primitive; |
| } |
| switch (signature.charAt(0)) { |
| case 'V': |
| return "void"; //$NON-NLS-1$ |
| case 'L': |
| return classSignatureToName(signature); |
| case '[': |
| return arraySignatureToName(signature); |
| case '(': |
| throw new InternalError( |
| JDIMessages.TypeImpl_Can__t_convert_method_signature_to_name_2); |
| } |
| throw new InternalError(JDIMessages.TypeImpl_Invalid_signature____10 |
| + signature + JDIMessages.TypeImpl___11); // |
| } |
| |
| private static String getPrimitiveSignatureToName(char signature) { |
| switch (signature) { |
| case 'Z': |
| return "boolean"; //$NON-NLS-1$ |
| case 'B': |
| return "byte"; //$NON-NLS-1$ |
| case 'C': |
| return "char"; //$NON-NLS-1$ |
| case 'S': |
| return "short"; //$NON-NLS-1$ |
| case 'I': |
| return "int"; //$NON-NLS-1$ |
| case 'J': |
| return "long"; //$NON-NLS-1$ |
| case 'F': |
| return "float"; //$NON-NLS-1$ |
| case 'D': |
| return "double"; //$NON-NLS-1$ |
| default: |
| return null; |
| } |
| } |
| |
| /** |
| * @returns Returns Jdwp Tag, converted from a JNI signature. |
| */ |
| public static byte signatureToTag(String signature) { |
| switch (signature.charAt(0)) { |
| case 'Z': |
| return BooleanValueImpl.tag; |
| case 'B': |
| return ByteValueImpl.tag; |
| case 'C': |
| return CharValueImpl.tag; |
| case 'S': |
| return ShortValueImpl.tag; |
| case 'I': |
| return IntegerValueImpl.tag; |
| case 'J': |
| return LongValueImpl.tag; |
| case 'F': |
| return FloatValueImpl.tag; |
| case 'D': |
| return DoubleValueImpl.tag; |
| case 'V': |
| return VoidValueImpl.tag; |
| case 'L': |
| return ObjectReferenceImpl.tag; |
| case '[': |
| return ArrayReferenceImpl.tag; |
| case '(': |
| throw new InternalError( |
| JDIMessages.TypeImpl_Can__t_covert_method_signature_to_tag___9 |
| + signature); |
| } |
| throw new InternalError(JDIMessages.TypeImpl_Invalid_signature____10 |
| + signature + JDIMessages.TypeImpl___11); // |
| } |
| |
| /** |
| * @returns Returns true if signature is an primitive signature. |
| */ |
| public static boolean isPrimitiveSignature(String signature) { |
| switch (signature.charAt(0)) { |
| case 'Z': |
| case 'B': |
| case 'C': |
| case 'S': |
| case 'I': |
| case 'J': |
| case 'F': |
| case 'D': |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * @returns Returns true if signature is void signature. |
| */ |
| public static boolean isVoidSignature(String signature) { |
| return (signature.charAt(0) == 'V'); |
| } |
| |
| } |