/******************************************************************************* * Copyright (c) 2005, 2009 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.jdt.internal.core.util; import java.util.ArrayList; import org.eclipse.jdt.core.Signature; import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.ast.Wildcard; import org.eclipse.jdt.internal.compiler.codegen.ConstantPool; /* * Converts a binding key into a signature */ public class KeyToSignature extends BindingKeyParser { public static final int SIGNATURE= 0; public static final int TYPE_ARGUMENTS= 1; public static final int DECLARING_TYPE= 2; public static final int THROWN_EXCEPTIONS= 3; public StringBuffer signature= new StringBuffer(); private int kind; private ArrayList arguments= new ArrayList(); private ArrayList typeArguments= new ArrayList(); private ArrayList typeParameters= new ArrayList(); private ArrayList thrownExceptions= new ArrayList(); private int mainTypeStart= -1; private int mainTypeEnd; private int typeSigStart= -1; public KeyToSignature(BindingKeyParser parser) { super(parser); this.kind= ((KeyToSignature)parser).kind; } public KeyToSignature(String key, int kind) { super(key); this.kind= kind; } public void consumeArrayDimension(char[] brakets) { this.signature.append(brakets); } public void consumeBaseType(char[] baseTypeSig) { this.typeSigStart= this.signature.length(); this.signature.append(baseTypeSig); } public void consumeCapture(int position) { this.signature.append('!'); this.signature.append(((KeyToSignature)this.arguments.get(0)).signature); } public void consumeLocalType(char[] uniqueKey) { this.signature= new StringBuffer(); // remove trailing semi-colon as it is added later in comsumeType() uniqueKey= CharOperation.subarray(uniqueKey, 0, uniqueKey.length - 1); CharOperation.replace(uniqueKey, '/', '.'); this.signature.append(uniqueKey); } public void consumeMethod(char[] selector, char[] methodSignature) { this.arguments= new ArrayList(); this.typeArguments= new ArrayList(); CharOperation.replace(methodSignature, '/', '.'); switch (this.kind) { case SIGNATURE: this.signature= new StringBuffer(); this.signature.append(methodSignature); break; case THROWN_EXCEPTIONS: if (CharOperation.indexOf('^', methodSignature) > 0) { char[][] types= Signature.getThrownExceptionTypes(methodSignature); int length= types.length; for (int i= 0; i < length; i++) { this.thrownExceptions.add(new String(types[i])); } } break; } } public void consumeMemberType(char[] simpleTypeName) { this.signature.append('$'); this.signature.append(simpleTypeName); } public void consumePackage(char[] pkgName) { this.signature.append(pkgName); } public void consumeParameterizedGenericMethod() { this.typeArguments= this.arguments; int typeParametersSize= this.arguments.size(); if (typeParametersSize > 0) { int sigLength= this.signature.length(); char[] methodSignature= new char[sigLength]; this.signature.getChars(0, sigLength, methodSignature, 0); char[][] typeParameterSigs= Signature.getTypeParameters(methodSignature); if (typeParameterSigs.length != typeParametersSize) return; this.signature= new StringBuffer(); // type parameters for (int i= 0; i < typeParametersSize; i++) typeParameterSigs[i]= CharOperation.concat(Signature.C_TYPE_VARIABLE, Signature.getTypeVariable(typeParameterSigs[i]), Signature.C_SEMICOLON); int paramStart= CharOperation.indexOf(Signature.C_PARAM_START, methodSignature); char[] typeParametersString= CharOperation.subarray(methodSignature, 0, paramStart); this.signature.append(typeParametersString); // substitute parameters this.signature.append(Signature.C_PARAM_START); char[][] parameters= Signature.getParameterTypes(methodSignature); for (int i= 0, parametersLength= parameters.length; i < parametersLength; i++) substitute(parameters[i], typeParameterSigs, typeParametersSize); this.signature.append(Signature.C_PARAM_END); // substitute return type char[] returnType= Signature.getReturnType(methodSignature); substitute(returnType, typeParameterSigs, typeParametersSize); // substitute exceptions char[][] exceptions= Signature.getThrownExceptionTypes(methodSignature); for (int i= 0, exceptionsLength= exceptions.length; i < exceptionsLength; i++) { this.signature.append(Signature.C_EXCEPTION_START); substitute(exceptions[i], typeParameterSigs, typeParametersSize); } } } /* * Substitutes the type variables referenced in the given parameter (a parameterized type signature) with the corresponding * type argument. * Appends the given parameter if it is not a parameterized type signature. */ private void substitute(char[] parameter, char[][] typeParameterSigs, int typeParametersLength) { for (int i= 0; i < typeParametersLength; i++) { if (CharOperation.equals(parameter, typeParameterSigs[i])) { String typeArgument= ((KeyToSignature)this.arguments.get(i)).signature.toString(); this.signature.append(typeArgument); return; } } int genericStart= CharOperation.indexOf(Signature.C_GENERIC_START, parameter); if (genericStart > -1) { this.signature.append(CharOperation.subarray(parameter, 0, genericStart)); char[][] parameters= Signature.getTypeArguments(parameter); this.signature.append(Signature.C_GENERIC_START); for (int j= 0, paramsLength= parameters.length; j < paramsLength; j++) substitute(parameters[j], typeParameterSigs, typeParametersLength); this.signature.append(Signature.C_GENERIC_END); this.signature.append(Signature.C_SEMICOLON); } else { // handle array, wildcard and capture int index= 0; int length= parameter.length; loop: while (index < length) { char current= parameter[index]; switch (current) { case Signature.C_CAPTURE: case Signature.C_EXTENDS: case Signature.C_SUPER: case Signature.C_ARRAY: this.signature.append(current); index++; break; default: break loop; } } if (index > 0) substitute(CharOperation.subarray(parameter, index, length), typeParameterSigs, typeParametersLength); else this.signature.append(parameter); } } public void consumeParameterizedType(char[] simpleTypeName, boolean isRaw) { if (simpleTypeName != null) { // member type this.signature.append('.'); this.signature.append(simpleTypeName); } if (!isRaw) { this.signature.append('<'); int length= this.arguments.size(); for (int i= 0; i < length; i++) { this.signature.append(((KeyToSignature)this.arguments.get(i)).signature); } this.signature.append('>'); this.typeArguments= this.arguments; this.arguments= new ArrayList(); } } public void consumeParser(BindingKeyParser parser) { this.arguments.add(parser); } public void consumeField(char[] fieldName) { if (this.kind == SIGNATURE) { this.signature= ((KeyToSignature)this.arguments.get(0)).signature; } } public void consumeException() { int size= this.arguments.size(); if (size > 0) { for (int i= 0; i < size; i++) { this.thrownExceptions.add(((KeyToSignature)this.arguments.get(i)).signature.toString()); } this.arguments= new ArrayList(); this.typeArguments= new ArrayList(); } } public void consumeFullyQualifiedName(char[] fullyQualifiedName) { this.typeSigStart= this.signature.length(); this.signature.append('L'); this.signature.append(CharOperation.replaceOnCopy(fullyQualifiedName, '/', '.')); } public void consumeSecondaryType(char[] simpleTypeName) { this.signature.append('~'); this.mainTypeStart= this.signature.lastIndexOf(".") + 1; //$NON-NLS-1$ if (this.mainTypeStart == 0) this.mainTypeStart= 1; // default package this.mainTypeEnd= this.signature.length(); this.signature.append(simpleTypeName); } public void consumeType() { // remove main type if needed if (this.mainTypeStart != -1) { this.signature.replace(this.mainTypeStart, this.mainTypeEnd, ""); //$NON-NLS-1$ } // parameter types int length= this.typeParameters.size(); if (length > 0) { StringBuffer typeParametersSig= new StringBuffer(); typeParametersSig.append('<'); for (int i= 0; i < length; i++) { char[] typeParameterSig= Signature.createTypeParameterSignature( (char[])this.typeParameters.get(i), new char[][] { ConstantPool.ObjectSignature }); typeParametersSig.append(typeParameterSig); // TODO (jerome) add type parameter bounds in binding key } typeParametersSig.append('>'); this.signature.insert(this.typeSigStart, typeParametersSig.toString()); this.typeParameters= new ArrayList(); } this.signature.append(';'); } public void consumeTypeParameter(char[] typeParameterName) { this.typeParameters.add(typeParameterName); } public void consumeTypeVariable(char[] position, char[] typeVariableName) { this.signature= new StringBuffer(); this.signature.append('T'); this.signature.append(typeVariableName); this.signature.append(';'); } public void consumeTypeWithCapture() { KeyToSignature keyToSignature= (KeyToSignature)this.arguments.get(0); this.signature= keyToSignature.signature; this.arguments= keyToSignature.arguments; this.typeArguments= keyToSignature.typeArguments; this.thrownExceptions= keyToSignature.thrownExceptions; } public void consumeWildCard(int wildCardKind) { // don't put generic type in signature this.signature= new StringBuffer(); switch (wildCardKind) { case Wildcard.UNBOUND: this.signature.append('*'); break; case Wildcard.EXTENDS: this.signature.append('+'); this.signature.append(((KeyToSignature)this.arguments.get(0)).signature); break; case Wildcard.SUPER: this.signature.append('-'); this.signature.append(((KeyToSignature)this.arguments.get(0)).signature); break; default: // malformed return; } } public String[] getThrownExceptions() { int length= this.thrownExceptions.size(); String[] result= new String[length]; for (int i= 0; i < length; i++) { result[i]= (String)this.thrownExceptions.get(i); } return result; } public String[] getTypeArguments() { int length= this.typeArguments.size(); String[] result= new String[length]; for (int i= 0; i < length; i++) { result[i]= ((KeyToSignature)this.typeArguments.get(i)).signature.toString(); } return result; } public BindingKeyParser newParser() { return new KeyToSignature(this); } /* (non-Javadoc) * @see java.lang.Object#toString() */ public String toString() { return this.signature.toString(); } }