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}