WALA/com.ibm.wala.core/src/com/ibm/wala/types/Descriptor.java

252 lines
6.8 KiB
Java

/*******************************************************************************
* Copyright (c) 2002 - 2006 IBM Corporation.
* 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 com.ibm.wala.types;
import java.util.Map;
import com.ibm.wala.classLoader.Language;
import com.ibm.wala.util.collections.HashMapFactory;
import com.ibm.wala.util.strings.ImmutableByteArray;
import com.ibm.wala.util.strings.StringStuff;
import com.ibm.wala.util.strings.UTF8Convert;
/**
* A method descriptor; something like: (Ljava/langString;)Ljava/lang/Class;
*
* Descriptors are canonical
*/
public final class Descriptor {
/**
* A mapping from Key -> Descriptor
*/
private static final Map<Key, Descriptor> map = HashMapFactory.make();
/**
* key holds the logical value of this descriptor
*/
private final Key key;
/**
* @param parameters the parameters for a descriptor
* @param returnType the return type
* @return the canonical representative for this descriptor value
*/
public static Descriptor findOrCreate(TypeName[] parameters, TypeName returnType) {
if (returnType == null) {
throw new IllegalArgumentException("null returnType");
}
if (parameters != null && parameters.length == 0) {
parameters = null;
}
Key k = new Key(returnType, parameters);
Descriptor result = map.get(k);
if (result == null) {
result = new Descriptor(k);
map.put(k, result);
}
return result;
}
/**
* @param b a byte array holding the string representation of this descriptor
* @return the canonical representative for this descriptor value
*/
public static Descriptor findOrCreate(Language l, ImmutableByteArray b) throws IllegalArgumentException {
TypeName returnType = StringStuff.parseForReturnTypeName(l, b);
TypeName[] parameters = StringStuff.parseForParameterNames(l, b);
Key k = new Key(returnType, parameters);
Descriptor result = map.get(k);
if (result == null) {
result = new Descriptor(k);
map.put(k, result);
}
return result;
}
public static Descriptor findOrCreate(ImmutableByteArray b) throws IllegalArgumentException {
return findOrCreate(Language.JAVA, b);
}
/**
* @param s string representation of this descriptor
* @return the canonical representative for this descriptor value
*/
public static Descriptor findOrCreateUTF8(String s) throws IllegalArgumentException {
return findOrCreateUTF8(Language.JAVA, s);
}
/**
* @param s string representation of this descriptor
* @return the canonical representative for this descriptor value
*/
public static Descriptor findOrCreateUTF8(Language l, String s) throws IllegalArgumentException {
byte[] b = UTF8Convert.toUTF8(s);
return findOrCreate(l, new ImmutableByteArray(b));
}
/**
* @param key "value" of this descriptor
*/
private Descriptor(Key key) {
this.key = key;
}
@Override
public boolean equals(Object obj) {
return this == obj;
}
@Override
public int hashCode() {
return key.hashCode();
}
@Override
public String toString() {
return key.toString();
}
/**
* @return a unicode string representation of this descriptor
*/
public String toUnicodeString() {
return key.toUnicodeString();
}
/**
* @return the name of the return type of this descriptor
*/
public TypeName getReturnType() {
return key.returnType;
}
/**
* @return the type names for the parameters in this descriptor
*/
public TypeName[] getParameters() {
return key.parameters;
}
/**
* @return number of parameters in this descriptor
*/
public int getNumberOfParameters() {
return key.parameters == null ? 0 : key.parameters.length;
}
/**
* value that defines a descriptor: used to canonicalize instances
*/
private static class Key {
final private TypeName returnType;
final private TypeName[] parameters;
final private int hashCode; // cached for efficiency
Key(TypeName returnType, TypeName[] parameters) {
this.returnType = returnType;
this.parameters = parameters;
if (parameters != null) {
assert parameters.length > 0;
}
hashCode = computeHashCode();
}
@Override
public int hashCode() {
return hashCode;
}
public int computeHashCode() {
int result = returnType.hashCode() * 5309;
if (parameters != null) {
for (int i = 0; i < parameters.length; i++) {
result += parameters[i].hashCode() * (5323 ^ i);
}
}
return result;
}
@Override
public boolean equals(Object obj) {
assert obj instanceof Key;
Key other = (Key) obj;
if (!returnType.equals(other.returnType)) {
return false;
}
if (parameters == null) {
return (other.parameters == null) ? true : false;
}
if (other.parameters == null) {
return false;
}
if (parameters.length != other.parameters.length) {
return false;
}
for (int i = 0; i < parameters.length; i++) {
if (!parameters[i].equals(other.parameters[i])) {
return false;
}
}
return true;
}
@Override
public String toString() {
StringBuffer result = new StringBuffer();
result.append("(");
if (parameters != null) {
for (TypeName p : parameters) {
result.append(p);
appendSemicolonIfNeeded(result, p);
}
}
result.append(")");
result.append(returnType);
appendSemicolonIfNeeded(result, returnType);
return result.toString();
}
public String toUnicodeString() {
StringBuffer result = new StringBuffer();
result.append("(");
if (parameters != null) {
for (TypeName p : parameters) {
result.append(p.toUnicodeString());
appendSemicolonIfNeeded(result, p);
}
}
result.append(")");
result.append(returnType);
appendSemicolonIfNeeded(result, returnType);
return result.toString();
}
private static void appendSemicolonIfNeeded(StringBuffer result, TypeName p) {
if (p.isArrayType()) {
TypeName e = p.getInnermostElementType();
String x = e.toUnicodeString();
if (x.startsWith("L") || x.startsWith("P")) {
result.append(";");
}
} else {
String x = p.toUnicodeString();
if (x.startsWith("L") || x.startsWith("P")) {
result.append(";");
}
}
}
}
}