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

260 lines
9.3 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.HashMap;
import com.ibm.wala.classLoader.Language;
import com.ibm.wala.util.collections.HashMapFactory;
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 method.
*/
public final class MethodReference extends MemberReference {
/**
* Used to canonicalize MethodReferences a mapping from Key -> MethodReference
*/
final private static HashMap<Key, MethodReference> dictionary = HashMapFactory.make();
public final static Atom newInstanceAtom = Atom.findOrCreateUnicodeAtom("newInstance");
private final static Descriptor newInstanceDesc = Descriptor.findOrCreateUTF8(Language.JAVA, "()Ljava/lang/Object;");
public final static MethodReference JavaLangClassNewInstance = findOrCreate(TypeReference.JavaLangClass, newInstanceAtom,
newInstanceDesc);
private final static Atom ctorNewInstanceAtom = Atom.findOrCreateUnicodeAtom("newInstance");
private final static Descriptor ctorNewInstanceDesc = Descriptor.findOrCreateUTF8(Language.JAVA, "([Ljava/lang/Object;)Ljava/lang/Object;");
public final static MemberReference JavaLangReflectCtorNewInstance = findOrCreate(TypeReference.JavaLangReflectConstructor,
ctorNewInstanceAtom, ctorNewInstanceDesc);
public final static Atom forNameAtom = Atom.findOrCreateUnicodeAtom("forName");
private final static Descriptor forNameDesc = Descriptor.findOrCreateUTF8(Language.JAVA, "(Ljava/lang/String;)Ljava/lang/Class;");
public final static MethodReference JavaLangClassForName = findOrCreate(TypeReference.JavaLangClass, forNameAtom, forNameDesc);
public final static Atom initAtom = Atom.findOrCreateUnicodeAtom("<init>");
public final static Descriptor defaultInitDesc = Descriptor.findOrCreateUTF8(Language.JAVA, "()V");
public final static Selector initSelector = new Selector(initAtom, defaultInitDesc);
public final static Atom clinitName = Atom.findOrCreateUnicodeAtom("<clinit>");
public final static Selector clinitSelector = new Selector(clinitName, defaultInitDesc);
public final static Atom finalizeName = Atom.findOrCreateUnicodeAtom("finalize");
public final static Selector finalizeSelector = new Selector(finalizeName, defaultInitDesc);
public final static Atom runAtom = Atom.findOrCreateUnicodeAtom("run");
public final static Descriptor runDesc = Descriptor.findOrCreateUTF8(Language.JAVA, "()Ljava/lang/Object;");
public final static Selector runSelector = new Selector(runAtom, runDesc);
public final static Atom equalsAtom = Atom.findOrCreateUnicodeAtom("equals");
public final static Descriptor equalsDesc = Descriptor.findOrCreateUTF8(Language.JAVA, "(Ljava/lang/Object;)Z");
public final static Selector equalsSelector = new Selector(equalsAtom, equalsDesc);
public final static MethodReference lambdaMetafactory =
findOrCreate(
TypeReference.LambdaMetaFactory,
Atom.findOrCreateUnicodeAtom("metafactory"),
Descriptor.findOrCreateUTF8("(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;"));
/**
* types of parameters to this method.
*/
final private TypeReference[] parameterTypes;
/**
* return type.
*/
private final TypeReference returnType;
/**
* Name and descriptor
*/
private final Selector selector;
/**
* Find or create the canonical MethodReference instance for the given tuple.
*
* @param mn the name of the member
* @param md the descriptor of the member
*/
public static synchronized MethodReference findOrCreate(TypeReference tref, Atom mn, Descriptor md) {
if (tref == null) {
throw new IllegalArgumentException("null tref");
}
Key key = new Key(tref, mn, md);
MethodReference val = dictionary.get(key);
if (val != null)
return val;
val = new MethodReference(key);
dictionary.put(key, val);
return val;
}
/**
* Find or create the canonical MethodReference instance for the given tuple.
*
* @param tref the type reference
* @param selector the selector for the method
* @throws IllegalArgumentException if selector is null
*/
public static synchronized MethodReference findOrCreate(TypeReference tref, Selector selector) {
if (selector == null) {
throw new IllegalArgumentException("selector is null");
}
return findOrCreate(tref, selector.getName(), selector.getDescriptor());
}
public static MethodReference findOrCreate(TypeReference t, String methodName, String descriptor) throws IllegalArgumentException {
return findOrCreate(Language.JAVA, t, methodName, descriptor);
}
public static MethodReference findOrCreate(Language l, TypeReference t, String methodName, String descriptor) throws IllegalArgumentException {
Descriptor d = Descriptor.findOrCreateUTF8(l, descriptor);
return findOrCreate(t, Atom.findOrCreateUnicodeAtom(methodName), d);
}
public static MethodReference findOrCreate(ClassLoaderReference loader, String methodClass, String methodName,
String methodSignature) throws IllegalArgumentException {
return findOrCreate(Language.JAVA, loader, methodClass, methodName, methodSignature);
}
public static MethodReference findOrCreate(Language l, ClassLoaderReference loader, String methodClass, String methodName,
String methodSignature) throws IllegalArgumentException {
TypeReference t = ShrikeUtil.makeTypeReference(loader, methodClass);
Atom name = Atom.findOrCreateUnicodeAtom(methodName);
Descriptor d = Descriptor.findOrCreateUTF8(l, methodSignature);
return findOrCreate(t, name, d);
}
/**
* @return the descriptor component of this member reference
*/
public final Descriptor getDescriptor() {
return selector.getDescriptor();
}
@Override
public final String toString() {
return "< " + getDeclaringClass().getClassLoader().getName() + ", " + getDeclaringClass().getName() + ", " + selector + " >";
}
MethodReference(Key key) {
super(key.type, key.name, key.hashCode());
selector = new Selector(key.name, key.descriptor);
TypeName[] parameterNames = key.descriptor.getParameters();
if (parameterNames != null) {
parameterTypes = new TypeReference[parameterNames.length];
} else {
parameterTypes = null;
}
ClassLoaderReference loader = getDeclaringClass().getClassLoader();
if (parameterNames != null) {
for (int i = 0; i < parameterNames.length; i++) {
parameterTypes[i] = TypeReference.findOrCreate(loader, parameterNames[i]);
}
}
TypeName r = key.descriptor.getReturnType();
returnType = TypeReference.findOrCreate(getDeclaringClass().getClassLoader(), r);
}
/**
* @return return type of the method
*/
public final TypeReference getReturnType() {
return returnType;
}
/**
* @return ith parameter to the method. This does NOT include the implicit "this" pointer.
*/
public final TypeReference getParameterType(int i) throws IllegalArgumentException {
if (parameterTypes == null || i >= parameterTypes.length) {
throw new IllegalArgumentException("illegal parameter number " + i + " for " + this);
}
return parameterTypes[i];
}
public boolean isInit() {
return getName().equals(MethodReference.initAtom);
}
/**
* @return something like: com.foo.bar.createLargeOrder(IILjava/lang/String;Ljava/sql/Date;)Ljava/lang/Integer;
*/
@Override
public String getSignature() {
// TODO: check that we're not calling this often.
String s = getDeclaringClass().getName().toString().substring(1).replace('/', '.') + "." + getName() + getDescriptor();
return s;
}
/**
* @return something like: createLargeOrder(IILjava.lang.String;SLjava.sql.Date;)Ljava.lang.Integer;
*/
public Selector getSelector() {
return selector;
}
/**
* This method does NOT include the implicit "this" parameter
*/
public int getNumberOfParameters() {
return parameterTypes == null ? 0 : parameterTypes.length;
}
/**
* An identifier/selector for methods.
*/
protected static class Key {
private final TypeReference type;
private final Atom name;
private final Descriptor descriptor;
Key(TypeReference type, Atom name, Descriptor descriptor) {
this.type = type;
this.name = name;
this.descriptor = descriptor;
}
@Override
public final int hashCode() {
return 7001 * type.hashCode() + 7013 * name.hashCode() + descriptor.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) && descriptor.equals(that.descriptor);
}
}
}