260 lines
9.3 KiB
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);
|
|
}
|
|
}
|
|
|
|
}
|