Copyright (c) 2000, 2016 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
/*******************************************************************************
* Copyright (c) 2000, 2016 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.jdt.internal.corext.template.java;
import java.util.Arrays;
import org.eclipse.jdt.core.CompletionProposal;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
Utilities for Signature operations.
See Also: - Signature
Since: 3.1
/**
* Utilities for Signature operations.
*
* @see Signature
* @since 3.1
*/
public final class SignatureUtil {
The signature of the null type. This type does not really exist in the
type system. It represents the bound of type variables that have no lower
bound, for example the parameter type to the add
method of
an instance of java.util.List<? extends Number>
.
The only possible value that has that type is null
.
The representation of the null type is the signature of a type variable
named null
("Tnull;"), which will only work if no such variable gets declared in the same context.
/**
* The signature of the null type. This type does not really exist in the
* type system. It represents the bound of type variables that have no lower
* bound, for example the parameter type to the <code>add</code> method of
* an instance of <code>java.util.List<? extends Number></code>.
* <p>
* The only possible value that has that type is <code>null</code>.
* </p>
* <p>
* The representation of the null type is the signature of a type variable
* named <code>null</code> ({@value}), which will only work if no such
* variable gets declared in the same context.
*/
private static final String NULL_TYPE_SIGNATURE= "Tnull;"; //$NON-NLS-1$
private static final char[] NULL_TYPE_SIGNATURE_ARRAY= NULL_TYPE_SIGNATURE.toCharArray();
The signature of java.lang.Object
("Ljava.lang.Object;"). /**
* The signature of <code>java.lang.Object</code> ({@value}).
*/
private static final String OBJECT_SIGNATURE= "Ljava.lang.Object;"; //$NON-NLS-1$
private static final char[] OBJECT_SIGNATURE_ARRAY= OBJECT_SIGNATURE.toCharArray();
private SignatureUtil() {
// do not instantiate
}
Returns true
if signature
is the
signature of the java.lang.Object
type.
Params: - signature – the signature
Returns: true
if signature
is the
signature of the java.lang.Object
type,
false
otherwise
/**
* Returns <code>true</code> if <code>signature</code> is the
* signature of the <code>java.lang.Object</code> type.
*
* @param signature the signature
* @return <code>true</code> if <code>signature</code> is the
* signature of the <code>java.lang.Object</code> type,
* <code>false</code> otherwise
*/
public static boolean isJavaLangObject(String signature) {
return OBJECT_SIGNATURE.equals(signature);
}
Returns the upper bound of a type signature. Returns the signature of java.lang.Object
if
signature
is a lower bound (? super T
); returns
the signature of the type T
of an upper bound (? extends T
)
or signature
itself if it is not a bound signature.
Params: - signature – the signature
Returns: the upper bound signature of signature
/**
* Returns the upper bound of a type signature. Returns the signature of <code>java.lang.Object</code> if
* <code>signature</code> is a lower bound (<code>? super T</code>); returns
* the signature of the type <code>T</code> of an upper bound (<code>? extends T</code>)
* or <code>signature</code> itself if it is not a bound signature.
*
* @param signature the signature
* @return the upper bound signature of <code>signature</code>
*/
public static String getUpperBound(String signature) {
return String.valueOf(getUpperBound(signature.toCharArray()));
}
Returns the upper bound of a type signature. Returns the signature of java.lang.Object
if
signature
is a lower bound (? super T
); returns
the signature of the type T
of an upper bound (? extends T
)
or signature
itself if it is not a bound signature.
Params: - signature – the signature
Returns: the upper bound signature of signature
/**
* Returns the upper bound of a type signature. Returns the signature of <code>java.lang.Object</code> if
* <code>signature</code> is a lower bound (<code>? super T</code>); returns
* the signature of the type <code>T</code> of an upper bound (<code>? extends T</code>)
* or <code>signature</code> itself if it is not a bound signature.
*
* @param signature the signature
* @return the upper bound signature of <code>signature</code>
*/
public static char[] getUpperBound(char[] signature) {
if (signature.length < 1)
return signature;
if (signature[0] == Signature.C_STAR)
return OBJECT_SIGNATURE_ARRAY;
int superIndex= indexOf(signature, Signature.C_SUPER);
if (superIndex == 0)
return OBJECT_SIGNATURE_ARRAY;
if (superIndex != -1) {
char afterSuper= signature[superIndex + 1];
if (afterSuper == Signature.C_STAR) {
char[] type= new char[signature.length - 1];
System.arraycopy(signature, 0, type, 0, superIndex);
type[superIndex]= Signature.C_STAR;
System.arraycopy(signature, superIndex + 2, type, superIndex + 1, signature.length - superIndex - 2);
return getUpperBound(type);
}
if (afterSuper == Signature.C_EXTENDS) {
int typeEnd= typeEnd(signature, superIndex + 1);
char[] type= new char[signature.length - (typeEnd - superIndex - 1)];
System.arraycopy(signature, 0, type, 0, superIndex);
type[superIndex]= Signature.C_STAR;
System.arraycopy(signature, typeEnd, type, superIndex + 1, signature.length - typeEnd);
return getUpperBound(type);
}
}
if (signature[0] == Signature.C_EXTENDS) {
char[] type= new char[signature.length - 1];
System.arraycopy(signature, 1, type, 0, signature.length - 1);
return type;
}
return signature;
}
Returns the lower bound of a type signature. Returns the null type
signature if signature
is a wildcard or upper bound (? extends T
);
returns the signature of the type T
of a lower bound (? super T
)
or signature
itself if it is not a bound signature.
Params: - signature – the signature
Returns: the lower bound signature of signature
/**
* Returns the lower bound of a type signature. Returns the null type
* signature if <code>signature</code> is a wildcard or upper bound (<code>? extends T</code>);
* returns the signature of the type <code>T</code> of a lower bound (<code>? super T</code>)
* or <code>signature</code> itself if it is not a bound signature.
*
* @param signature the signature
* @return the lower bound signature of <code>signature</code>
*/
public static String getLowerBound(String signature) {
return String.valueOf(getLowerBound(signature.toCharArray()));
}
Returns the lower bound of a type signature. Returns the null type
signature if signature
is a wildcard or upper bound (? extends T
);
returns the signature of the type T
of a lower bound (? super T
)
or signature
itself if it is not a bound signature.
Params: - signature – the signature
Returns: the lower bound signature of signature
/**
* Returns the lower bound of a type signature. Returns the null type
* signature if <code>signature</code> is a wildcard or upper bound (<code>? extends T</code>);
* returns the signature of the type <code>T</code> of a lower bound (<code>? super T</code>)
* or <code>signature</code> itself if it is not a bound signature.
*
* @param signature the signature
* @return the lower bound signature of <code>signature</code>
*/
public static char[] getLowerBound(char[] signature) {
if (signature.length < 1)
return signature;
if (signature.length == 1 && signature[0] == Signature.C_STAR)
return signature;
int superIndex= indexOf(signature, Signature.C_EXTENDS);
if (superIndex == 0)
return NULL_TYPE_SIGNATURE_ARRAY;
if (superIndex != -1) {
char afterSuper= signature[superIndex + 1];
if (afterSuper == Signature.C_STAR || afterSuper == Signature.C_EXTENDS)
// impossible captured type
return NULL_TYPE_SIGNATURE_ARRAY;
}
char[][] typeArguments= Signature.getTypeArguments(signature);
for (int i= 0; i < typeArguments.length; i++)
if (Arrays.equals(typeArguments[i], NULL_TYPE_SIGNATURE_ARRAY))
return NULL_TYPE_SIGNATURE_ARRAY;
if (signature[0] == Signature.C_SUPER) {
char[] type= new char[signature.length - 1];
System.arraycopy(signature, 1, type, 0, signature.length - 1);
return type;
}
return signature;
}
private static int indexOf(char[] signature, char ch) {
for (int i= 0; i < signature.length; i++) {
if (signature[i] == ch)
return i;
}
return -1;
}
Returns the fully qualified type name of the given signature, with any
type parameters and arrays erased.
Params: - signature – the signature
Throws: - IllegalArgumentException – if the signature is syntactically incorrect
Returns: the fully qualified type name of the signature
/**
* Returns the fully qualified type name of the given signature, with any
* type parameters and arrays erased.
*
* @param signature the signature
* @return the fully qualified type name of the signature
* @throws IllegalArgumentException if the signature is syntactically incorrect
*/
public static String stripSignatureToFQN(String signature) throws IllegalArgumentException {
signature= Signature.getTypeErasure(signature);
signature= Signature.getElementType(signature);
return Signature.toString(signature);
}
Returns the qualified signature corresponding to
signature
.
Params: - signature – the signature to qualify
- context – the type inside which an unqualified type will be
resolved to find the qualifier, or
null
if no
context is available
Returns: the qualified signature
/**
* Returns the qualified signature corresponding to
* <code>signature</code>.
*
* @param signature the signature to qualify
* @param context the type inside which an unqualified type will be
* resolved to find the qualifier, or <code>null</code> if no
* context is available
* @return the qualified signature
*/
public static String qualifySignature(final String signature, final IType context) {
if (context == null)
return signature;
String qualifier= Signature.getSignatureQualifier(signature);
if (qualifier.length() > 0)
return signature;
String elementType= Signature.getElementType(signature);
String erasure= Signature.getTypeErasure(elementType);
String simpleName= Signature.getSignatureSimpleName(erasure);
String genericSimpleName= Signature.getSignatureSimpleName(elementType);
int dim= Signature.getArrayCount(signature);
try {
String[][] strings= context.resolveType(simpleName);
if (strings != null && strings.length > 0)
qualifier= strings[0][0];
} catch (JavaModelException e) {
// ignore - not found
}
if (qualifier.length() == 0)
return signature;
String qualifiedType= Signature.toQualifiedName(new String[] {qualifier, genericSimpleName});
String qualifiedSignature= Signature.createTypeSignature(qualifiedType, true);
String newSignature= Signature.createArraySignature(qualifiedSignature, dim);
return newSignature;
}
Takes a method signature
[< typeVariableName : formalTypeDecl >] ( paramTypeSig1* ) retTypeSig
and returns it with any parameter signatures filtered through
getLowerBound
and the return type filtered through
getUpperBound
. Any preceding formal type variable
declarations are removed.
TODO this is a temporary workaround for
https://bugs.eclipse.org/bugs/show_bug.cgi?id=83600
Params: - signature – the method signature to convert
Returns: the signature with no bounded types
/**
* Takes a method signature
* <code>[< typeVariableName : formalTypeDecl >] ( paramTypeSig1* ) retTypeSig</code>
* and returns it with any parameter signatures filtered through
* <code>getLowerBound</code> and the return type filtered through
* <code>getUpperBound</code>. Any preceding formal type variable
* declarations are removed.
* <p>
* TODO this is a temporary workaround for
* https://bugs.eclipse.org/bugs/show_bug.cgi?id=83600
* </p>
*
* @param signature the method signature to convert
* @return the signature with no bounded types
*/
public static char[] unboundedSignature(char[] signature) {
if (signature == null || signature.length < 2)
return signature;
final boolean BUG_83600= true;
// XXX the signatures from CompletionRequestor contain a superfluous '+'
// before type parameters to parameter types
if (BUG_83600) {
signature= fix83600(signature);
}
StringBuilder res= new StringBuilder("("); //$NON-NLS-1$
char[][] parameters= Signature.getParameterTypes(signature);
for (int i= 0; i < parameters.length; i++) {
char[] param= parameters[i];
res.append(getLowerBound(param));
}
res.append(')');
res.append(getUpperBound(Signature.getReturnType(signature)));
return res.toString().toCharArray();
}
TODO this is a temporary workaround for
https://bugs.eclipse.org/bugs/show_bug.cgi?id=83600 and
https://bugs.eclipse.org/bugs/show_bug.cgi?id=85293
Params: - signature – the method signature to convert
Returns: the fixed signature
/**
* TODO this is a temporary workaround for
* https://bugs.eclipse.org/bugs/show_bug.cgi?id=83600 and
* https://bugs.eclipse.org/bugs/show_bug.cgi?id=85293
*
* @param signature the method signature to convert
* @return the fixed signature
*/
public static char[] fix83600(char[] signature) {
if (signature == null || signature.length < 2)
return signature;
return Signature.removeCapture(signature);
}
private static int typeEnd(char[] signature, int pos) {
int depth= 0;
while (pos < signature.length) {
switch (signature[pos]) {
case Signature.C_GENERIC_START:
depth++;
break;
case Signature.C_GENERIC_END:
if (depth == 0)
return pos;
depth--;
break;
case Signature.C_SEMICOLON:
if (depth == 0)
return pos + 1;
break;
}
pos++;
}
return pos + 1;
}
public static String getQualifiedTypeName(CompletionProposal proposal) {
return String.valueOf(Signature.toCharArray(Signature
.getTypeErasure(proposal.getSignature())));
}
public static String getSimpleTypeName(CompletionProposal proposal) {
return Signature.getSimpleName(getQualifiedTypeName(proposal));
}
}