647 lines
21 KiB
Plaintext
647 lines
21 KiB
Plaintext
|
package slangc.model;
|
||
|
|
||
|
import slang.data.List;
|
||
|
import slangc.api.Reporter;
|
||
|
import slangc.bytecode.MethodSignature;
|
||
|
import slangc.bytecode.TypeSignature;
|
||
|
import slangc.model.clauses.Arguments;
|
||
|
import slangc.model.expressions.SuperConstructorCallExpression;
|
||
|
import slangc.model.expressions.ThisConstructorCallExpression;
|
||
|
import slangc.model.statements.BlockStatement;
|
||
|
import slangc.model.statements.ExpressionStatement;
|
||
|
import slangc.parser.Branch;
|
||
|
import slangc.parser.ErrorType;
|
||
|
import slangc.parser.Node;
|
||
|
import slangc.parser.NodeType;
|
||
|
|
||
|
public class MethodModel extends MemberModel implements StatementOwner {
|
||
|
BlockStatement body = null;
|
||
|
ParameterSet parameters = null;
|
||
|
TypeModel returnType = null;
|
||
|
TypeModel[] exceptions = null;
|
||
|
List<LocalStorageModel> locals = null;
|
||
|
MethodModel prototype = null;
|
||
|
|
||
|
/** Constructor for synthetic methods which copy an existing method signature. */
|
||
|
public MethodModel(TypeModel owner, String name, MethodModel copySignatureFrom) {
|
||
|
super(owner, name, null);
|
||
|
// TODO: It might be worth making a deep copy of the parameters so they're actually usable by synthetic code
|
||
|
parameters = copySignatureFrom.parameters;
|
||
|
returnType = copySignatureFrom.returnType;
|
||
|
exceptions = copySignatureFrom.exceptions;
|
||
|
setAttributes(copySignatureFrom.getAttributes());
|
||
|
this.prototype = copySignatureFrom;
|
||
|
}
|
||
|
|
||
|
public MethodModel(TypeModel owner, String name, Branch source) {
|
||
|
super(owner, name, source);
|
||
|
|
||
|
parameters = new ParameterSet(this);
|
||
|
|
||
|
if (!isStaticInitialisation()) {
|
||
|
Branch p = source.getNodeType() == NodeType.METHOD_DECLARATION ?
|
||
|
(Branch) source.getSubnode(source.countSubnodes() - 4)
|
||
|
: (Branch) source.getSubnode(source.countSubnodes() - 3);
|
||
|
Branch l = (Branch) p.getSubnode(1);
|
||
|
int goodparams = 0;
|
||
|
for (int i = 0; i < l.countSubnodes(); i++) {
|
||
|
Node n = l.getSubnode(i);
|
||
|
if (n.getNodeType() != NodeType.COMMA) {
|
||
|
goodparams++;
|
||
|
}
|
||
|
}
|
||
|
for (int i = 0; i < l.countSubnodes(); i++) {
|
||
|
/* Parameters are indexed in bytecode by their stack position (relative to
|
||
|
* the method call frame info), which gives the last parameter index -1,
|
||
|
* the second-last index -2 and so on (since the last parameter will be
|
||
|
* pushed just before the method call frame starts).
|
||
|
*/
|
||
|
int negindex = (0 - goodparams) + parameters.countParameters();
|
||
|
Node n = l.getSubnode(i);
|
||
|
if (n.getNodeType() != NodeType.COMMA) {
|
||
|
parameters.addParameter(new ParameterModel(this, negindex /*parameters.countParameters()*/, (Branch) n));
|
||
|
}
|
||
|
}
|
||
|
exceptions = unpackExceptions(((Branch)(source.getSubnode(source.countSubnodes() - 2))));
|
||
|
}
|
||
|
|
||
|
if (isConstructor()) {
|
||
|
//Log.line("Owner is " + owner.fullName());
|
||
|
returnType = owner;
|
||
|
} else if (isStaticInitialisation()) {
|
||
|
returnType = null; // TODO: Better "void" handling
|
||
|
} else {
|
||
|
Branch t = (Branch) source.getSubnode(2);
|
||
|
if (t.getNodeType() == NodeType.NO_RETURN_TYPE) {
|
||
|
returnType = null; // TODO: Better "void" handling
|
||
|
} else {
|
||
|
returnType = ((UserTypeModel)owner).resolveTypeReference(t.getSubnode(0));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (hasBody()) {
|
||
|
body = new BlockStatement(this, (Branch) ((Branch)(source.getSubnode(source.countSubnodes() - 1))).getSubnode(0));
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
private TypeModel[] unpackExceptions(Branch b) {
|
||
|
if (b.getNodeType() == NodeType.NO_THROWS) {
|
||
|
return null;
|
||
|
} else {
|
||
|
Branch list = (Branch)b.getSubnode(0);
|
||
|
if (list.countSubnodes() == 0) {
|
||
|
return null;
|
||
|
}
|
||
|
int count = 0;
|
||
|
for (int i = 0; i < list.countSubnodes(); i++) {
|
||
|
if (list.getSubnode(i).getNodeType() != NodeType.COMMA) {
|
||
|
count++;
|
||
|
}
|
||
|
}
|
||
|
TypeModel[] result = new TypeModel[count];
|
||
|
count = 0;
|
||
|
for (int i = 0; i < list.countSubnodes(); i++) {
|
||
|
if (list.getSubnode(i).getNodeType() != NodeType.COMMA) {
|
||
|
result[count] = getOwner().resolveTypeReference(list.getSubnode(i));
|
||
|
if (result[count] == null) {
|
||
|
list.getSubnode(i).annotate(ErrorType.INTERNAL_ERROR, "Failed to resolve type reference");
|
||
|
//throw new Error("TODO BAD");
|
||
|
}
|
||
|
count++;
|
||
|
}
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public int countExceptions() {
|
||
|
if (exceptions == null) {
|
||
|
return 0;
|
||
|
} else {
|
||
|
return exceptions.length;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public TypeModel getException(int i) {
|
||
|
return exceptions[i];
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public MemberCategory getCategory() {
|
||
|
return MemberCategory.METHOD;
|
||
|
}
|
||
|
|
||
|
public boolean isConstructor() {
|
||
|
return getName().equals("this");/*return getSource().getNodeType() == NodeType.CONSTRUCTOR_DECLARATION;*/
|
||
|
}
|
||
|
|
||
|
public ParameterSet getParameters() {
|
||
|
return parameters;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* If this is an instance constructor, checks if it's body begins with a call to another/super constructor and
|
||
|
* marks that constructor's location as approved.
|
||
|
* @return true if this is an instance constructor starting with an explicit (and now marked "approved")
|
||
|
* call to another/super constructor, otherwise false.
|
||
|
*/
|
||
|
public boolean checkExplicitBaseConstructorCall(boolean includingThisConstructorCall) {
|
||
|
if (isConstructor() && hasBody()) {
|
||
|
if (getBody() instanceof BlockStatement) {
|
||
|
BlockStatement b = (BlockStatement) getBody();
|
||
|
if (b.countInnerStatements() > 0) {
|
||
|
StatementModel first = b.getInnerStatement(0);
|
||
|
if (first instanceof ExpressionStatement) {
|
||
|
ExpressionModel expr = ((ExpressionStatement)first).getExpression();
|
||
|
if (expr instanceof ThisConstructorCallExpression) {
|
||
|
((ThisConstructorCallExpression)expr).setApprovedLocation(true);
|
||
|
if (includingThisConstructorCall) {
|
||
|
return true;
|
||
|
}
|
||
|
} else if (expr instanceof SuperConstructorCallExpression) {
|
||
|
((SuperConstructorCallExpression)expr).setApprovedLocation(true);
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public boolean isStaticInitialisation() {
|
||
|
return getSource() != null && getSource().getNodeType() == NodeType.STATIC_CONSTRUCTOR_DECLARATION;
|
||
|
}
|
||
|
|
||
|
public boolean hasBody() {
|
||
|
if (body != null) {
|
||
|
return true;
|
||
|
} else if (isSynthetic()) {
|
||
|
return body != null;
|
||
|
} else {
|
||
|
return getSource().getSubnode(getSource().countSubnodes() - 1).getNodeType() == NodeType.METHOD_BODY;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public BlockStatement getBody() {
|
||
|
return body;
|
||
|
}
|
||
|
|
||
|
public boolean hasReturnType() {
|
||
|
return returnType != null;
|
||
|
}
|
||
|
|
||
|
public TypeModel getReturnType() {
|
||
|
return returnType;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void dump(Reporter reporter, String indent, String incr) {
|
||
|
// TODO Auto-generated method stub
|
||
|
super.dump(reporter, indent, incr);
|
||
|
|
||
|
if (hasReturnType()) {
|
||
|
reporter.note("DUMP", indent + incr + "> Return type is " + getReturnType());
|
||
|
} else {
|
||
|
reporter.note("DUMP", indent + incr + "[no/void return type]");
|
||
|
}
|
||
|
|
||
|
if (parameters.countParameters() == 0) {
|
||
|
reporter.note("DUMP", indent + incr + "[no parameters]");
|
||
|
} else {
|
||
|
reporter.note("DUMP", indent + incr + "> " + parameters.countParameters() + " parameters:");
|
||
|
}
|
||
|
|
||
|
for (int i = 0; i < parameters.countParameters(); i++) {
|
||
|
parameters.getParameter(i).dump(reporter, indent + incr + incr, incr);
|
||
|
}
|
||
|
|
||
|
if (hasBody()) {
|
||
|
reporter.note("DUMP", indent + incr + "> Method body: ...");
|
||
|
//body.dump(reporter, indent + incr + incr, incr);
|
||
|
} else {
|
||
|
reporter.note("DUMP", indent + incr + "[no method body]");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean isStatic() {
|
||
|
return super.isStatic() /*|| isConstructor()*/ || isStaticInitialisation();
|
||
|
}
|
||
|
|
||
|
//@Override
|
||
|
public TypeModel resolveType(Node typeReference) {
|
||
|
return ((UserTypeModel)getOwner()).resolveTypeReference(typeReference);
|
||
|
}
|
||
|
//@Override
|
||
|
public MethodModel getMethodOrField() {
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
//@Override
|
||
|
public InnerTypeScope getTypeScope() {
|
||
|
return getOwner();
|
||
|
}
|
||
|
|
||
|
//@Override
|
||
|
public Named lookupSimpleName(String name) {
|
||
|
if (parameters != null && parameters.hasParameter(name)) {
|
||
|
return parameters.getParameter(name);
|
||
|
}
|
||
|
return getOwner().lookupSimpleName(name);
|
||
|
}
|
||
|
|
||
|
public MethodModel[] lookupSimpleMethod(String name) {
|
||
|
return getOwner().lookupSimpleMethod(name);
|
||
|
}
|
||
|
|
||
|
public String signatureString() {
|
||
|
String result = getName();
|
||
|
result += "(";
|
||
|
|
||
|
if (parameters != null) {
|
||
|
for (int i = 0; i < parameters.countParameters(); i++) {
|
||
|
if (i != 0) {
|
||
|
result += ",";
|
||
|
}
|
||
|
ParameterModel m = parameters.getParameter(i);
|
||
|
result += m.getStorageType().fullName();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
result += ")";
|
||
|
|
||
|
if (returnType != null) {
|
||
|
result += ":" + returnType.fullName();
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public String toString() {
|
||
|
return getOwner().toString() + "." + signatureString();
|
||
|
}
|
||
|
|
||
|
public boolean overrides(MethodModel other) {
|
||
|
//System.err.println("Checking if " + this + " overrides " + other + "...");
|
||
|
// Perform obvious checks first - if names don't match we don't override
|
||
|
if (!getName().equals(other.getName())) {
|
||
|
//System.err.println("Doesn't override - names don't match");
|
||
|
return false;
|
||
|
}
|
||
|
// If other type isn't an ancestor of this type we don't override
|
||
|
if (!getOwner().inherits(other.getOwner())) {
|
||
|
//System.err.println("Doesn't override - doesn't fit hierarchy");
|
||
|
return false;
|
||
|
}
|
||
|
// In the special case of constructors, they will be considered to logically override any inherited constructors
|
||
|
if (isConstructor()) {
|
||
|
//System.err.println("Does kind-of override - is constructor");
|
||
|
return true;
|
||
|
}
|
||
|
// If names/types can lead to a potential override, we need to check parameters/return types
|
||
|
if (!canOverrideParameters(other.parameters)) {
|
||
|
//System.err.println("Doesn't override - parameters don't match");
|
||
|
return false;
|
||
|
}
|
||
|
if (!canOverrideReturn(other.returnType)) {
|
||
|
//System.err.println("Doesn't override - return types are incompatible");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//System.err.println("Signatures match so it does override");
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public boolean canOverrideParameters(ParameterSet other) {
|
||
|
if (parameters.countParameters() != other.countParameters()) {
|
||
|
//System.err.println("Patemeter counts don't match");
|
||
|
return false;
|
||
|
}
|
||
|
for (int i = 0; i < parameters.countParameters(); i++) {
|
||
|
ParameterModel thisp = parameters.getParameter(i);
|
||
|
ParameterModel otherp = other.getParameter(i);
|
||
|
if (thisp.getStorageType() != otherp.getStorageType()) {
|
||
|
//System.err.println("Storage types " + thisp.getStorageType() + " and " + otherp.getStorageType() + " don't match");
|
||
|
return false;
|
||
|
/*if (!(thisp.getStorageType() instanceof UserTypeModel) || !(otherp.getStorageType() instanceof UserTypeModel)) {
|
||
|
return false;
|
||
|
}*/
|
||
|
/*if (!thisp.getStorageType().isAssignableFrom(otherp.getStorageType())) {
|
||
|
return false;
|
||
|
}*/
|
||
|
|
||
|
}
|
||
|
}
|
||
|
// If nothing mismatched we can override
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public boolean canOverrideReturn(TypeModel otherReturnType) {
|
||
|
if (returnType == otherReturnType) {
|
||
|
return true;
|
||
|
} else if (returnType != null && otherReturnType != null) {
|
||
|
return otherReturnType.isAssignableFrom(returnType);
|
||
|
} else {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int resolveExpressions() {
|
||
|
if (hasBody()) {
|
||
|
return getBody().resolveExpressions();
|
||
|
} else {
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public boolean isApplicableToArguments(Arguments arguments, boolean allowVarargs) {
|
||
|
ExpressionModel[] exprs = arguments.getSubexpressions();
|
||
|
if ((!allowVarargs || !parameters.isVarargs()) && exprs.length != parameters.countParameters()) {
|
||
|
return false;
|
||
|
} else if (allowVarargs && parameters.isVarargs() && exprs.length < parameters.countNonVarargParameters()) {
|
||
|
return false;
|
||
|
}
|
||
|
for (int i = 0; i < exprs.length; i++) {
|
||
|
ExpressionResult r = exprs[i].getResult();
|
||
|
if (r.resolvesToValueOrNull()) {
|
||
|
if (r.getKind() == ExpressionResult.Kind.NULL) {
|
||
|
if (!parameters.getParameterType(i, allowVarargs).isObjectType()) {
|
||
|
return false;
|
||
|
}
|
||
|
} else {
|
||
|
if (!parameters.getParameterType(i, allowVarargs).isAssignableFrom(r.getValueType())) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* If nothing was a mismatch, it should be good to go! */
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public boolean isLeftAssignableFromRight(ParameterSet left, ParameterSet right, boolean allowVarargs) {
|
||
|
if (left.countParameters() != right.countParameters()) {
|
||
|
return false;
|
||
|
}
|
||
|
for (int i = 0; i < left.countParameters(); i++) {
|
||
|
if (!left.getParameterType(i, allowVarargs).isAssignableFrom(right.getParameterType(i, allowVarargs))) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public int compareApplicabilityOfArguments(MethodModel other, Arguments arguments, boolean allowVarargs) {
|
||
|
if (isLeftAssignableFromRight(this.parameters, other.parameters, allowVarargs)) {
|
||
|
return -1;
|
||
|
} else if (isLeftAssignableFromRight(other.parameters, this.parameters, allowVarargs)) {
|
||
|
return 1;
|
||
|
} else {
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static int compareApplicabilityOfArguments(MethodModel[] lhs, MethodModel[] rhs, Arguments arguments, boolean allowVarargs) {
|
||
|
if (lhs.length == 0 && rhs.length > 0) {
|
||
|
return 1;
|
||
|
} else if (rhs.length == 0 && lhs.length > 0) {
|
||
|
return -1;
|
||
|
}
|
||
|
for (int i = 0; i < lhs.length; i++) {
|
||
|
for (int j = 0; i < rhs.length; j++) {
|
||
|
int comp = lhs[i].compareApplicabilityOfArguments(rhs[j], arguments, allowVarargs);
|
||
|
if (comp != 0) {
|
||
|
return comp;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
public static MethodModel[] addArrays(MethodModel[] a, MethodModel[] b) {
|
||
|
MethodModel[] c = new MethodModel[a.length + b.length];
|
||
|
for (int i = 0; i < c.length; i++) {
|
||
|
c[i] = i < a.length ? a[i] : b[i - a.length];
|
||
|
}
|
||
|
return c;
|
||
|
}
|
||
|
|
||
|
public static MethodModel[] arrayWithout(MethodModel[] a, MethodModel b) {
|
||
|
MethodModel[] c = new MethodModel[0];
|
||
|
for (int i = 0; i < a.length; i++) {
|
||
|
if (a[i] != b) {
|
||
|
c = addArrays(c, new MethodModel[] {a[i]});
|
||
|
}
|
||
|
}
|
||
|
return c;
|
||
|
}
|
||
|
|
||
|
public static boolean arrayContains(MethodModel[] a, MethodModel b) {
|
||
|
for (int i = 0; i < a.length; i++) {
|
||
|
if (a[i] == b) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns a new array of MethodModel instances where any duplicate entries or those
|
||
|
* made irrelevant by others in the list which override them are removed.
|
||
|
*
|
||
|
* <p/>
|
||
|
* This shouldn't normally be used directly, but is used internally by findApplicableMethods/bestApplicableMethod.
|
||
|
* @param availableMethods
|
||
|
* @return
|
||
|
*/
|
||
|
public static MethodModel[] findRelevantMethods(MethodModel[] availableMethods, boolean checkOverrides) {
|
||
|
MethodModel[] result = new MethodModel[0];
|
||
|
|
||
|
for (int i = 0; i < availableMethods.length; i++) {
|
||
|
MethodModel thisMethod = availableMethods[i];
|
||
|
boolean willAdd = true;
|
||
|
for (int j = 0; j < availableMethods.length; j++) {
|
||
|
if (checkOverrides && i != j) {
|
||
|
MethodModel otherMethod = availableMethods[j];
|
||
|
if (otherMethod.overrides(thisMethod)) {
|
||
|
//System.err.println("Method " + thisMethod + " is overridden by " + otherMethod + " so will be ignored");
|
||
|
willAdd = false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// Avoid adding any already-existing results so this method can also remove duplicates
|
||
|
if (willAdd && !arrayContains(result, availableMethods[i])) {
|
||
|
//System.err.println("Method " + thisMethod + " will be considered");
|
||
|
result = addArrays(result, new MethodModel[] {availableMethods[i]});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Narrows down a list of available methods/constructors (i.e. which have been looked up by name) to
|
||
|
* those which are applicable to the given arguments. This also avoids adding any methods which are
|
||
|
* overridden by a method already on the list.
|
||
|
*
|
||
|
* <p/>
|
||
|
* This shouldn't normally be used directly, instead bestApplicableMethods should be used to get a
|
||
|
* reduced list.
|
||
|
*
|
||
|
* @param availableMethods
|
||
|
* @param arguments
|
||
|
* @return
|
||
|
*/
|
||
|
public static MethodModel[] findApplicableMethods(MethodModel[] availableMethods, Arguments arguments, boolean allowVarargs) {
|
||
|
// Begin by removing any duplicate methods
|
||
|
// (note, overridden methods should already be excluded UNLESS they also occur in scope
|
||
|
// actually, that probably never happens anyway. Doesn't seem to be an issue?)
|
||
|
availableMethods = findRelevantMethods(availableMethods, false);
|
||
|
|
||
|
MethodModel[] result = new MethodModel[0];
|
||
|
|
||
|
for (int i = 0; i < availableMethods.length; i++) {
|
||
|
//System.err.println("Checking if " + availableMethods[i] + " matches " + arguments);
|
||
|
if (availableMethods[i].isApplicableToArguments(arguments, allowVarargs)) {
|
||
|
//System.err.println("Match.");
|
||
|
result = addArrays(result, new MethodModel[] {availableMethods[i]});
|
||
|
//System.err.println("Result length: " + result.length);
|
||
|
} else {
|
||
|
//System.err.println("No match.");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns an array of the "most applicable" methods (based on the arguments) from an array of
|
||
|
* available choices.
|
||
|
*
|
||
|
* <p/>
|
||
|
* This method first calls findApplicableMethods to limit to those which are applicable.
|
||
|
* If no methods are applicable, an empty array is returned. If more than one are applicable, then
|
||
|
* this method will try to select the "most applicable" from those, ideally returning exactly
|
||
|
* one method but including any ambiguous ones if necessary.
|
||
|
*
|
||
|
* @param availableMethods
|
||
|
* @param arguments
|
||
|
* @return
|
||
|
*/
|
||
|
public static MethodModel[] bestApplicableMethods(MethodModel[] availableMethods, Arguments arguments, boolean allowVarargs) {
|
||
|
MethodModel[] applicable = findApplicableMethods(availableMethods, arguments, allowVarargs);
|
||
|
/* If there's only one applicable method (or none) then we don't have to do any more work to
|
||
|
* choose between them.
|
||
|
*/
|
||
|
if (applicable.length < 2) {
|
||
|
return applicable;
|
||
|
}
|
||
|
|
||
|
MethodModel[] mostApplicable = new MethodModel[0];
|
||
|
|
||
|
for (int i = 0; i < applicable.length; i++) {
|
||
|
if (mostApplicable.length == 0) {
|
||
|
mostApplicable = new MethodModel[] {applicable[i]};
|
||
|
} else {
|
||
|
MethodModel[] newMostApplicable = new MethodModel[0];
|
||
|
for (int j = 0; j < mostApplicable.length; j++) {
|
||
|
int comp = applicable[i].compareApplicabilityOfArguments(mostApplicable[j], arguments, allowVarargs);
|
||
|
if (comp < 0) {
|
||
|
newMostApplicable = addArrays(newMostApplicable, new MethodModel[] {mostApplicable[j]});
|
||
|
} else if (comp > 0) {
|
||
|
newMostApplicable = addArrays(newMostApplicable, new MethodModel[] {applicable[i]});
|
||
|
} else {
|
||
|
newMostApplicable = addArrays(newMostApplicable, new MethodModel[] {mostApplicable[j], applicable[i]});
|
||
|
}
|
||
|
}
|
||
|
mostApplicable = newMostApplicable;
|
||
|
}
|
||
|
/*
|
||
|
MethodModel[] newArray = new MethodModel[] {applicable[i]};
|
||
|
int slangc = compareApplicabilityOfArguments(mostApplicable, newArray, arguments);
|
||
|
if (slangc < 0) {
|
||
|
mostApplicable = newArray;
|
||
|
} else if (slangc > 0) {
|
||
|
// the existing ones are more applicable, no further action is required
|
||
|
} else {
|
||
|
// they are equally applicable, so we add the two lists together
|
||
|
mostApplicable = addArrays(mostApplicable, newArray);
|
||
|
}
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
return mostApplicable;
|
||
|
}
|
||
|
|
||
|
public MethodSignature getMethodSignature() {
|
||
|
TypeSignature[] argsigs = new TypeSignature[parameters.countParameters()];
|
||
|
for (int i = 0; i < argsigs.length; i++) {
|
||
|
argsigs[i] = parameters.getParameter(i).getStorageType().getTypeSignature();
|
||
|
}
|
||
|
MethodSignature.Kind kind;
|
||
|
if (isStaticInitialisation()) {
|
||
|
kind = MethodSignature.Kind.STATIC_INIT;
|
||
|
} else if (isConstructor()) {
|
||
|
kind = MethodSignature.Kind.CONSTRUCTOR;
|
||
|
} else if (getOwner().getTypeType() == TypeType.INTERFACE || getOwner().getTypeType() == TypeType.INTERFACE_TEMPLATE) {
|
||
|
kind = isStatic() ? MethodSignature.Kind.STATIC_METHOD : MethodSignature.Kind.INTERFACE_METHOD;
|
||
|
} else {
|
||
|
kind = isStatic() ? MethodSignature.Kind.STATIC_METHOD : MethodSignature.Kind.INSTANCE_METHOD;
|
||
|
}
|
||
|
return new MethodSignature(getOwner().getTypeSignature(), kind, returnType == null ? TypeSignature.VOID : returnType.getTypeSignature(), getName(), argsigs);
|
||
|
}
|
||
|
|
||
|
public int countParameters() {
|
||
|
return parameters.countParameters();
|
||
|
}
|
||
|
|
||
|
public ParameterModel getParameter(int indexFromLeft) {
|
||
|
return parameters.getParameter(indexFromLeft);
|
||
|
}
|
||
|
|
||
|
private List<LocalStorageModel> getLocals() {
|
||
|
if (locals == null) {
|
||
|
locals = new List<LocalStorageModel>();
|
||
|
for (int i = 0; i < countParameters(); i++) {
|
||
|
locals.append(parameters.getParameter(i));
|
||
|
}
|
||
|
}
|
||
|
return locals;
|
||
|
}
|
||
|
|
||
|
public int countLocals() {
|
||
|
return getLocals().count();
|
||
|
}
|
||
|
|
||
|
void localAdded(LocalVariableSlot l) {
|
||
|
getLocals().append(l);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int getFlags() {
|
||
|
int f = super.getFlags();
|
||
|
|
||
|
if (isConstructor() || isStaticInitialisation()) {
|
||
|
f |= Flags.MASK_CONSTRUCTOR;
|
||
|
}
|
||
|
|
||
|
if (isSynthetic()) {
|
||
|
f |= Flags.MASK_SYNTHETIC;
|
||
|
}
|
||
|
|
||
|
return f;
|
||
|
}
|
||
|
|
||
|
public MethodModel getPrototype() {
|
||
|
return prototype;
|
||
|
}
|
||
|
}
|