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