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}