
net.oneandone.mork.classfile.MethodRef Maven / Gradle / Ivy
/**
* Copyright 1&1 Internet AG, https://github.com/1and1/
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.oneandone.mork.classfile;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
/**
* Reference of a class or interface method.
* I don't distinguish class and interface methods by different
* types - in parallel to Java's treatment of primitive types
* as Class objects.
*/
public class MethodRef extends Reference {
public final ClassRef owner;
public final boolean ifc;
public final String name;
public final ClassRef[] argumentTypes;
public final ClassRef returnType;
public static final String INIT = "";
public MethodRef(Method m) {
Class>[] args;
int i;
owner = new ClassRef(m.getDeclaringClass());
ifc = false;
name = m.getName();
args = m.getParameterTypes();
argumentTypes = new ClassRef[args.length];
for (i = 0; i < args.length; i++) {
argumentTypes[i] = new ClassRef(args[i]);
}
returnType = new ClassRef(m.getReturnType());
}
public MethodRef(Constructor> c) {
Class>[] args;
int i;
owner = new ClassRef(c.getDeclaringClass());
ifc = false;
name = MethodRef.INIT;
args = c.getParameterTypes();
argumentTypes = new ClassRef[args.length];
for (i = 0; i < args.length; i++) {
argumentTypes[i] = new ClassRef(args[i]);
}
returnType = ClassRef.VOID;
}
public MethodRef(ClassRef owner, boolean ifc, ClassRef returnType, String name, ClassRef ... argumentTypes) {
this.owner = owner;
this.ifc = ifc;
this.name = name;
this.argumentTypes = argumentTypes;
this.returnType = returnType;
}
@Override
public ClassRef getOwner() {
return owner;
}
@Override
public MethodDef lookup(Repository repository) throws ResolveException {
return lookup((ClassDef) owner.resolve(repository), repository);
}
private MethodDef lookup(ClassDef def, Repository repository) throws ResolveException {
MethodDef method;
method = def.lookupMethod(name, argumentTypes);
if (method != null && method.returnType.equals(returnType)) {
return method;
}
// order doesn't matter - Javac rejects ambiguous references
for (ClassRef next : def.interfaces) {
method = lookup((ClassDef) next.resolve(repository), repository);
if (method != null) {
return method;
}
}
if (def.superClass != null) {
return lookup((ClassDef) def.superClass.resolve(repository), repository);
} else {
return null;
}
}
//-- convinience methods to create references
public static MethodRef meth(ClassRef owner, ClassRef returnType, String name) {
return new MethodRef(owner, false, returnType, name,
ClassRef.NONE);
}
public static MethodRef meth(ClassRef owner, ClassRef returnType, String name, ClassRef arg0) {
return new MethodRef(owner, false, returnType, name,
new ClassRef[] { arg0 });
}
public static MethodRef meth(ClassRef owner, ClassRef returnType,
String name, ClassRef arg0, ClassRef arg1) {
return new MethodRef(owner, false, returnType, name,
new ClassRef[] { arg0, arg1 });
}
public static MethodRef meth(ClassRef owner, ClassRef returnType,
String name, ClassRef arg0, ClassRef arg1, ClassRef arg2) {
return new MethodRef(owner, false, returnType, name,
new ClassRef[] { arg0, arg1, arg2 });
}
public static MethodRef meth(ClassRef owner, ClassRef returnType,
String name,
ClassRef arg0, ClassRef arg1, ClassRef arg2, ClassRef arg3) {
return new MethodRef(owner, false, returnType, name,
new ClassRef[] { arg0, arg1, arg2, arg3 });
}
public static MethodRef ifc(ClassRef owner, ClassRef returnType, String name) {
return new MethodRef(owner, true, returnType, name,
ClassRef.NONE);
}
public static MethodRef ifc(ClassRef owner, ClassRef returnType, String name, ClassRef arg0) {
return new MethodRef(owner, true, returnType, name,
new ClassRef[] { arg0 });
}
public static MethodRef ifc(ClassRef owner, ClassRef returnType,
String name, ClassRef arg0, ClassRef arg1) {
return new MethodRef(owner, true, returnType, name,
new ClassRef[] { arg0, arg1 });
}
public static MethodRef ifc(ClassRef owner, ClassRef returnType,
String name, ClassRef arg0, ClassRef arg1, ClassRef arg2) {
return new MethodRef(owner, true, returnType, name,
new ClassRef[] { arg0, arg1, arg2 });
}
public static MethodRef ifc(ClassRef owner, ClassRef returnType,
String name,
ClassRef arg0, ClassRef arg1, ClassRef arg2, ClassRef arg3) {
return new MethodRef(owner, true, returnType, name,
new ClassRef[] { arg0, arg1, arg2, arg3 });
}
public static MethodRef constr(ClassRef cl, ClassRef[] args) {
return new MethodRef(cl, false, ClassRef.VOID, INIT, args);
}
public static MethodRef constr(ClassRef cl) {
return constr(cl, ClassRef.NONE);
}
public static MethodRef constr(ClassRef cl, ClassRef arg0) {
return constr(cl, new ClassRef[] { arg0 });
}
public static MethodRef constr(ClassRef cl, ClassRef arg0, ClassRef arg1) {
return constr(cl, new ClassRef[] { arg0, arg1 });
}
public static MethodRef constr(ClassRef cl, ClassRef arg0, ClassRef arg1, ClassRef arg2) {
return constr(cl, new ClassRef[] { arg0, arg1, arg2 });
}
public static MethodRef constr(ClassRef cl, ClassRef arg0, ClassRef arg1, ClassRef arg2, ClassRef arg3) {
return constr(cl, new ClassRef[] { arg0, arg1, arg2, arg3 });
}
//--
public int argSize() {
int result;
int i;
result = 0;
for (i = 0; i < argumentTypes.length; i++) {
result += argumentTypes[i].operandSize();
}
return result;
}
@Override
public boolean equals(Object obj) {
MethodRef ref;
int i;
if (!(obj instanceof MethodRef)) {
return false;
}
ref = (MethodRef) obj;
if (!(owner.equals(ref.owner)
&& (ifc == ref.ifc)
&& name.equals(ref.name)
&& returnType.equals(ref.returnType)
&& (argumentTypes.length == ref.argumentTypes.length))) {
return false;
}
for (i = 0; i < argumentTypes.length; i++) {
if (!argumentTypes[i].equals(ref.argumentTypes[i])) {
return false;
}
}
return true;
}
@Override
public int hashCode() {
return name.hashCode();
}
public String toDescriptor() {
return toDescriptor(argumentTypes, returnType);
}
public static String toDescriptor(ClassRef[] args, ClassRef result) {
StringBuilder buffer;
int i;
buffer = new StringBuilder();
buffer.append('(');
for (i = 0; i < args.length; i++) {
buffer.append(args[i].toFieldDescriptor());
}
buffer.append(')');
buffer.append(result.toFieldDescriptor());
return buffer.toString();
}
public static ClassRef forReturnType(String descriptor) {
int i;
i = descriptor.indexOf(')');
if (i == -1) {
throw new RuntimeException();
}
return (ClassRef) ClassRef.forFieldDescriptor(descriptor, i + 1, descriptor.length())[0];
}
public static ClassRef[] forArgumentTypes(String descriptor) {
int ofs, length;
List lst;
ClassRef[] result;
Object[] tmp;
length = descriptor.length();
if ((length < 2) || (descriptor.charAt(0) != '(')) {
throw new RuntimeException();
}
ofs = 1;
lst = new ArrayList();
while ((ofs < length) && (descriptor.charAt(ofs) != ')')) {
tmp = ClassRef.forFieldDescriptor(descriptor, ofs, length);
lst.add((ClassRef) tmp[0]);
ofs = (Integer) tmp[1];
}
result = new ClassRef[lst.size()];
lst.toArray(result);
return result;
}
@Override
public String toString() {
StringBuilder result;
int i;
result = new StringBuilder();
result.append(returnType);
result.append(' ');
result.append(owner);
result.append('.');
result.append(name);
result.append('(');
for (i = 0; i < argumentTypes.length; i++) {
if (i > 0) {
result.append(", ");
}
result.append(argumentTypes[i]);
}
result.append(')');
return result.toString();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy