package gb.svnfilter.findbugs;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeParameter;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
/**
* Utility to get a resolved binary signature from a given method.
*
* @author Marc R. Hoffmann
* @version $Revision: $
*/
public final class SignatureResolver {
private static final String EMPTY = ""; //$NON-NLS-1$
private static final String OBJECT = "Ljava/lang/Object;"; //$NON-NLS-1$
private static final char SLASH = '/';
/**
* Extracts the parameter part from the given signature, i.e. the substring
* contained in braces.
*
* @param signature
* method signature
* @return parameter part only
*/
public static String getParameters(final String signature) {
final int pos = signature.lastIndexOf(')');
// avoid String instances for methods without parameters
return pos == 1 ? EMPTY : signature.substring(1, pos);
}
/**
* Extracts the resolved binary parameters from the given method
*
* @param method
* method to resolve
* @return binary parameter specification
* @throws JavaModelException
*/
public static String getParameters(final IMethod method)
throws JavaModelException {
if (method.isBinary()) {
return getParameters(method.getSignature());
}
final StringBuffer buffer = new StringBuffer();
final String[] parameterTypes = method.getParameterTypes();
for (int i = 0; i < parameterTypes.length; i++) {
resolveArrayParameterType(method, parameterTypes[i], buffer);
}
return buffer.toString();
}
private static final void resolveArrayParameterType(final IMethod method,
final String parameterType, final StringBuffer result)
throws JavaModelException {
final int arrayCount = Signature.getArrayCount(parameterType);
for (int i = 0; i < arrayCount; i++) {
result.append(Signature.C_ARRAY);
}
resolveParameterType(method, parameterType.substring(arrayCount), result);
}
private static final void resolveParameterType(final IMethod method,
final String parameterType, final StringBuffer result)
throws JavaModelException {
final char kind = parameterType.charAt(0);
switch (kind) {
case Signature.C_UNRESOLVED:
final String identifier = parameterType.substring(1, parameterType
.length() - 1);
if (resolveType(method.getDeclaringType(), identifier, result)) {
return;
}
if (resolveTypeParameter(method, identifier, result)) {
return;
}
break;
}
result.append(parameterType);
}
private static final boolean resolveType(final IType scope,
final String identifier, final StringBuffer result)
throws JavaModelException {
final String[][] types = scope.resolveType(Signature
.getTypeErasure(identifier));
if (types == null || types.length != 1) {
return false;
}
result.append(Signature.C_RESOLVED);
final String qualifier = types[0][0];
if (qualifier.length() > 0) {
replace(qualifier, Signature.C_DOT, SLASH, result);
result.append(SLASH);
}
replace(types[0][1], Signature.C_DOT, Signature.C_DOLLAR, result);
result.append(Signature.C_SEMICOLON);
return true;
}
private static final boolean resolveTypeParameter(final IMethod method,
final String identifier, final StringBuffer result)
throws JavaModelException {
IType type = method.getDeclaringType();
if (resolveTypeParameter(type, method.getTypeParameters(), identifier,
result)) {
return true;
}
while (type != null) {
if (resolveTypeParameter(type, type.getTypeParameters(), identifier,
result)) {
return true;
}
type = type.getDeclaringType();
}
return false;
}
private static final boolean resolveTypeParameter(final IType context,
final ITypeParameter[] typeParameters, final String identifier,
final StringBuffer result) throws JavaModelException {
for (int i = 0; i < typeParameters.length; i++) {
final ITypeParameter p = typeParameters[i];
if (identifier.equals(p.getElementName())) {
final String[] bounds = p.getBounds();
if (bounds.length == 0) {
result.append(OBJECT);
return true;
}
return resolveType(context, bounds[0], result);
}
}
return false;
}
private static final void replace(final String source, final char oldChar,
final char newChar, final StringBuffer result) {
final int len = source.length();
for (int i = 0; i < len; i++) {
final char c = source.charAt(i);
result.append(c == oldChar ? newChar : c);
}
}
}