| /******************************************************************************* |
| * Copyright (c) 2005, 2013 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 |
| * Stephan Herrmann - Contribution for |
| * Bug 425183 - [1.8][inference] make CaptureBinding18 safe |
| *******************************************************************************/ |
| 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 |
| */ |
| @SuppressWarnings({"rawtypes", "unchecked"}) |
| 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); |
| } |
| |
| @Override |
| public void consumeCapture18ID(int id, int position) { |
| // see https://bugs.eclipse.org/429264 |
| this.signature.append("!*"); // pretend a 'capture-of ?' //$NON-NLS-1$ |
| } |
| |
| 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 (1 for the 'L') |
| int i = 0; |
| // we need to preserve the array if needed |
| while (this.signature.charAt(i) == Signature.C_ARRAY) { |
| this.mainTypeStart ++; |
| i++; |
| } |
| } |
| 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(); |
| } |
| |
| } |