/*******************************************************************************
* 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.HashMap;
import com.ibm.wala.util.collections.HashMapFactory;
import com.ibm.wala.util.debug.Assertions;
import com.ibm.wala.util.debug.UnimplementedError;
import com.ibm.wala.util.shrike.ShrikeUtil;
import com.ibm.wala.util.strings.Atom;
/**
* A class to represent the reference in a class file to a field.
*/
public final class FieldReference extends MemberReference {
private final static boolean DEBUG = false;
/**
* Used to canonicalize MemberReferences a mapping from Key -> MemberReference
*/
final private static HashMap<Key, FieldReference> dictionary = HashMapFactory.make();
private final TypeReference fieldType;
@Override
public String getSignature() {
return getDeclaringClass().getName() + "." + getName() + " " + getFieldType().getName();
}
/**
* Find or create the canonical MemberReference instance for the given tuple.
*
* @param mn the name of the member
*/
public static synchronized FieldReference findOrCreate(TypeReference tref, Atom mn, TypeReference fieldType) {
if (tref == null) {
throw new IllegalArgumentException("null tref");
}
Key key = new Key(tref, mn, fieldType);
FieldReference val = dictionary.get(key);
if (val != null) {
return val;
}
val = new FieldReference(key, fieldType);
dictionary.put(key, val);
return val;
}
/**
* Find or create the canonical MemberReference instance for the given tuple.
*/
public static FieldReference findOrCreate(ClassLoaderReference loader, String classType, String fieldName, String fieldType)
throws IllegalArgumentException {
TypeReference c = ShrikeUtil.makeTypeReference(loader, classType);
TypeReference ft = ShrikeUtil.makeTypeReference(loader, fieldType);
Atom name = Atom.findOrCreateUnicodeAtom(fieldName);
return findOrCreate(c, name, ft);
}
private FieldReference(Key key, TypeReference fieldType) {
super(key.type, key.name, key.hashCode());
this.fieldType = fieldType;
if (DEBUG) {
if (getName().toString().indexOf('.') > -1)
throw new UnimplementedError();
if (fieldType.toString().indexOf('.') > -1)
Assertions.UNREACHABLE("Field name: " + fieldType.toString());
if (getName().toString().length() == 0)
throw new UnimplementedError();
if (fieldType.toString().length() == 0)
throw new UnimplementedError();
}
}
/**
* @return the descriptor component of this member reference
*/
public final TypeReference getFieldType() {
return fieldType;
}
@Override
public final String toString() {
return "< " + getDeclaringClass().getClassLoader().getName() + ", " + getDeclaringClass().getName() + ", " + getName() + ", "
+ fieldType + " >";
}
/**
* An identifier/selector for fields.
*/
protected static class Key {
final TypeReference type;
final Atom name;
private final TypeReference fieldType;
Key(TypeReference type, Atom name, TypeReference fieldType) {
this.type = type;
this.name = name;
this.fieldType = fieldType;
}
@Override
public final int hashCode() {
return 7487 * type.hashCode() + name.hashCode();
}
@Override
public final boolean equals(Object other) {
assert other != null && this.getClass().equals(other.getClass());
Key that = (Key) other;
return type.equals(that.type) && name.equals(that.name) && fieldType.equals(that.fieldType);
}
}
}