001/*
002 * Copyright (c) 2012-2017 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 */
009
010package org.eclipse.golo.runtime;
011
012import java.lang.invoke.MethodType;
013import java.lang.invoke.MethodHandle;
014import java.lang.reflect.Method;
015
016import static java.lang.reflect.Modifier.*;
017
018/**
019 * Encapsulate informations about a runtime method call.
020 */
021public class MethodInvocation {
022
023  private final String name;
024  private final Class<?> receiverClass;
025  private final Object[] arguments;
026  private final int arity;
027  private final String[] argumentNames;
028  private final MethodType type;
029
030  MethodInvocation(String name, MethodType type, Object[] args, String[] argNames) {
031    this.name = name;
032    this.receiverClass = args[0].getClass();
033    this.arguments = args;
034    this.arity = args.length;
035    this.type = type;
036    this.argumentNames = argNames;
037  }
038
039  public String name() {
040    return name;
041  }
042
043  public Class<?> receiverClass() {
044    return receiverClass;
045  }
046
047  public Object[] arguments() {
048    return arguments;
049  }
050
051  public int arity() {
052    return arity;
053  }
054
055  public String[] argumentNames() {
056    return argumentNames;
057  }
058
059  public MethodType type() {
060    return type;
061  }
062
063  private boolean isLastArgumentAnArray() {
064    return arity > 0
065      && arguments.length == arity
066      && arguments[arity - 1] instanceof Object[];
067  }
068
069  public MethodHandle coerce(MethodHandle target) {
070    if (target.isVarargsCollector() && isLastArgumentAnArray()) {
071      return target.asFixedArity().asType(type);
072    }
073    return target.asType(type);
074  }
075
076  public boolean match(Method method) {
077    return method.getName().equals(name)
078      && isPublic(method.getModifiers())
079      && !isAbstract(method.getModifiers())
080      && TypeMatching.argumentsMatch(method, arguments);
081  }
082
083  /**
084   * returns a new invocation having the given name.
085   */
086  MethodInvocation withName(String newName) {
087    return new MethodInvocation(newName, type, arguments, argumentNames);
088  }
089
090  @Override
091  public String toString() {
092    return name + type + java.util.Arrays.asList(arguments);
093  }
094
095
096}