2020-08-26 11:23:24 +03:00
|
|
|
|
|
|
|
using System;
|
|
|
|
using System.Reflection;
|
|
|
|
using System.Globalization;
|
|
|
|
using System.Runtime.Serialization;
|
|
|
|
|
|
|
|
namespace system.reflection
|
|
|
|
{
|
|
|
|
|
|
|
|
[System.Serializable]
|
|
|
|
public sealed class RuntimeMethodInfo : MethodInfo, ISerializable
|
|
|
|
{
|
|
|
|
#pragma warning disable 0436
|
|
|
|
[java.attr.RetainType] public java.lang.reflect.Method JavaMethod;
|
|
|
|
#pragma warning restore 0436
|
|
|
|
[java.attr.RetainType] public string originalName;
|
|
|
|
[java.attr.RetainType] public string strippedName;
|
|
|
|
[java.attr.RetainType] public system.RuntimeType reflectedType;
|
|
|
|
[java.attr.RetainType] public object[] typeArguments;
|
|
|
|
|
|
|
|
[java.attr.RetainType] public int genericFlags;
|
|
|
|
const int flgGenericMethod = 0x10;
|
|
|
|
const int flgGenericMethodDefinition = 0x20;
|
|
|
|
const int flgContainsGenericParameters = 0x40;
|
|
|
|
const int flgCombineGenericArguments = 0x80;
|
|
|
|
|
|
|
|
//
|
|
|
|
// GetMethod (called by system.RuntimeType.GetMethodImpl)
|
|
|
|
//
|
|
|
|
|
|
|
|
public static MethodInfo GetMethod(string name, BindingFlags bindingAttr,
|
|
|
|
Binder binder, CallingConventions callConvention,
|
|
|
|
Type[] types, ParameterModifier[] modifiers,
|
|
|
|
RuntimeType initialType)
|
|
|
|
{
|
|
|
|
//
|
|
|
|
// validate parameters
|
|
|
|
//
|
|
|
|
|
|
|
|
if (name == null)
|
|
|
|
throw new ArgumentNullException("name");
|
|
|
|
if (binder != null)
|
|
|
|
throw new PlatformNotSupportedException("non-null binder");
|
|
|
|
if (callConvention != CallingConventions.Any)
|
|
|
|
throw new PlatformNotSupportedException("calling convention must be Any");
|
|
|
|
if (types != null)
|
|
|
|
throw new PlatformNotSupportedException("non-null types");
|
|
|
|
if (modifiers != null)
|
|
|
|
throw new PlatformNotSupportedException("non-null modifiers");
|
|
|
|
|
|
|
|
//
|
|
|
|
// calculate modifier AND mask and result for matches
|
|
|
|
//
|
|
|
|
|
|
|
|
int modifierMask = 0;
|
|
|
|
int modifierValue = 0;
|
|
|
|
|
|
|
|
BindingFlags chk = bindingAttr & (BindingFlags.Public | BindingFlags.NonPublic);
|
|
|
|
if (chk != (BindingFlags.Public | BindingFlags.NonPublic))
|
|
|
|
{
|
|
|
|
if (chk == 0) // if neither, no methods will match
|
|
|
|
return null;
|
|
|
|
// methods with internal access are converted to public access,
|
|
|
|
// so we cannot honor the distinction between Public and NonPublic
|
|
|
|
/*
|
|
|
|
modifierMask |= java.lang.reflect.Modifier.PUBLIC;
|
|
|
|
if (chk == BindingFlags.Public)
|
|
|
|
modifierValue |= java.lang.reflect.Modifier.PUBLIC;
|
|
|
|
*/
|
|
|
|
bindingAttr &= ~chk;
|
|
|
|
}
|
|
|
|
|
|
|
|
chk = bindingAttr & (BindingFlags.Static | BindingFlags.Instance);
|
|
|
|
if (chk != (BindingFlags.Static | BindingFlags.Instance))
|
|
|
|
{
|
|
|
|
if (chk == 0) // if neither, no methods will match
|
|
|
|
return null;
|
|
|
|
modifierMask |= java.lang.reflect.Modifier.STATIC;
|
|
|
|
if (chk == BindingFlags.Static)
|
|
|
|
modifierValue |= java.lang.reflect.Modifier.STATIC;
|
|
|
|
bindingAttr &= ~chk;
|
|
|
|
}
|
|
|
|
|
|
|
|
RuntimeType stopAtType = null;
|
|
|
|
if ((bindingAttr & BindingFlags.DeclaredOnly) != 0)
|
|
|
|
{
|
|
|
|
stopAtType = initialType;
|
|
|
|
bindingAttr &= ~BindingFlags.DeclaredOnly;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bindingAttr != 0)
|
|
|
|
throw new PlatformNotSupportedException("bad binding flags " + bindingAttr);
|
|
|
|
|
|
|
|
//
|
|
|
|
// collect methods from class and base classes
|
|
|
|
//
|
|
|
|
|
|
|
|
var currentType = initialType;
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
#pragma warning disable 0436
|
|
|
|
java.lang.reflect.Method[] javaMethods =
|
|
|
|
(java.lang.reflect.Method[]) (object)
|
|
|
|
currentType.JavaClassForArray().getDeclaredMethods();
|
|
|
|
#pragma warning restore 0436
|
|
|
|
|
|
|
|
foreach (var javaMethod in javaMethods)
|
|
|
|
{
|
|
|
|
int jmodifiers = javaMethod.getModifiers();
|
|
|
|
if ((jmodifiers & modifierMask) == modifierValue)
|
|
|
|
{
|
|
|
|
string originalName = javaMethod.getName();
|
|
|
|
// note the actual suffix character below is configured
|
|
|
|
// in CilMain.cs, with special considerations for Android.
|
|
|
|
// we list all possible characters here, just in case.
|
|
|
|
int idx = originalName.IndexOf('\u00AB'); // U+00AB Left-Pointing Double Angle Quotation Mark
|
|
|
|
if (idx == -1)
|
|
|
|
idx = originalName.IndexOf('\u00A1'); // U+00A1 Inverted Exclamation Mark
|
|
|
|
if (idx == -1)
|
|
|
|
idx = originalName.IndexOf('(');
|
|
|
|
if (idx == -1)
|
|
|
|
idx = originalName.IndexOf('!');
|
|
|
|
var compareName =
|
|
|
|
(idx == -1) ? originalName : originalName.Substring(0, idx);
|
|
|
|
|
|
|
|
if (name == compareName)
|
|
|
|
{
|
|
|
|
javaMethod.setAccessible(true);
|
|
|
|
return new RuntimeMethodInfo(javaMethod, jmodifiers, initialType,
|
|
|
|
originalName, compareName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
currentType = (system.RuntimeType) currentType.BaseType;
|
|
|
|
if (currentType == stopAtType)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// constructor
|
|
|
|
//
|
|
|
|
|
|
|
|
#pragma warning disable 0436
|
|
|
|
private RuntimeMethodInfo(java.lang.reflect.Method javaMethod, int modifiers,
|
|
|
|
system.RuntimeType reflectedType,
|
|
|
|
string originalName, string strippedName)
|
|
|
|
#pragma warning restore 0436
|
|
|
|
{
|
|
|
|
this.JavaMethod = javaMethod;
|
|
|
|
this.reflectedType = reflectedType;
|
|
|
|
this.originalName = originalName;
|
|
|
|
this.strippedName = strippedName;
|
|
|
|
|
|
|
|
if (modifiers == -1) // if called from MakeGenericMethod
|
|
|
|
return;
|
|
|
|
|
|
|
|
// analyze the method and the declaring type in order to decide what
|
|
|
|
// type of a generic method this is. the general idea is:
|
|
|
|
// if the method takes more generic parameters, than the number of
|
|
|
|
// arguments in the type, then it is a generic method definition.
|
|
|
|
|
|
|
|
int originalNameLen = originalName.Length;
|
|
|
|
char lastChar = (originalNameLen > 0)
|
|
|
|
? originalName[originalNameLen - 1]
|
|
|
|
: (char) 0;
|
|
|
|
// the actual suffix character is configured in CilMain.cs
|
|
|
|
if (lastChar == '\u00A1' || lastChar == '!') // U+00A1 Inverted Exclamation Mark
|
|
|
|
{
|
|
|
|
if ((modifiers & java.lang.reflect.Modifier.STATIC) == 0)
|
|
|
|
{
|
|
|
|
// if an instance method takes any type arguments at all,
|
|
|
|
// then it must be a generic method definition
|
|
|
|
genericFlags |= flgGenericMethod
|
|
|
|
| flgGenericMethodDefinition
|
|
|
|
| flgContainsGenericParameters;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// count the number of type arguments in the declaring type
|
|
|
|
var typeArgsInType = reflectedType.GetGenericArguments();
|
|
|
|
int numTypeArgsInType = typeArgsInType.Length;
|
|
|
|
|
|
|
|
// count the number of type parameters in the method signature
|
|
|
|
int numTypeArgsInMethod = 0;
|
|
|
|
var paramTypes = javaMethod.getParameterTypes();
|
|
|
|
int paramIndex = paramTypes.Length;
|
|
|
|
while (paramIndex-- > 0)
|
|
|
|
{
|
|
|
|
var paramType = paramTypes[paramIndex];
|
|
|
|
if (paramType != (java.lang.Class) typeof(System.Type))
|
|
|
|
break;
|
|
|
|
numTypeArgsInMethod++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (numTypeArgsInMethod == numTypeArgsInType)
|
|
|
|
{
|
|
|
|
// a static method that takes a number of type parameters
|
|
|
|
// equal to the number of arguments in the declaring type.
|
|
|
|
// this means it is not a generic method, but it may not
|
|
|
|
// be invokable, if the declaring type is not concrete.
|
|
|
|
|
|
|
|
if (reflectedType.ContainsGenericParameters)
|
|
|
|
genericFlags |= flgContainsGenericParameters;
|
|
|
|
|
|
|
|
else if (reflectedType.IsGenericType)
|
|
|
|
genericFlags |= flgCombineGenericArguments;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (numTypeArgsInMethod > numTypeArgsInType)
|
|
|
|
{
|
|
|
|
// a static method that takes more parameters than the
|
|
|
|
// declaring type, i.e. it is a generic method definition.
|
|
|
|
genericFlags |= flgGenericMethod
|
|
|
|
| flgGenericMethodDefinition
|
|
|
|
| flgContainsGenericParameters;
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
throw new TypeLoadException(originalName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// a method that does not take any type argument may still be
|
|
|
|
// not invokable, if the reflected type is not a concrete type.
|
|
|
|
// note that this is true only for instance methods, as static
|
|
|
|
// methods in a generic type will always take type arguments.
|
|
|
|
|
|
|
|
if ((modifiers & java.lang.reflect.Modifier.STATIC) == 0)
|
|
|
|
{
|
|
|
|
if (reflectedType.ContainsGenericParameters)
|
|
|
|
genericFlags |= flgContainsGenericParameters;
|
|
|
|
|
|
|
|
else if (reflectedType.IsGenericType)
|
|
|
|
genericFlags |= flgCombineGenericArguments;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// MakeGenericMethod
|
|
|
|
//
|
|
|
|
|
|
|
|
public override MethodInfo MakeGenericMethod(Type[] typeArguments)
|
|
|
|
{
|
|
|
|
if (! IsGenericMethodDefinition)
|
|
|
|
throw new InvalidOperationException();
|
|
|
|
if (typeArguments == null)
|
|
|
|
throw new ArgumentNullException();
|
|
|
|
|
|
|
|
var implicitTypeArgs = reflectedType.GetGenericArguments();
|
|
|
|
int implicitTypeArgsCount = implicitTypeArgs.Length;
|
|
|
|
var explicitTypeArgsCount = typeArguments.Length;
|
|
|
|
int combinedTypeArgsCount = implicitTypeArgsCount + explicitTypeArgsCount;
|
|
|
|
|
|
|
|
var combinedTypeArgs = new object[combinedTypeArgsCount];
|
|
|
|
java.lang.System.arraycopy(
|
|
|
|
/* from */ implicitTypeArgs, 0,
|
|
|
|
/* into */ combinedTypeArgs, 0,
|
|
|
|
/* count */ implicitTypeArgsCount);
|
|
|
|
java.lang.System.arraycopy(
|
|
|
|
/* from */ typeArguments, 0,
|
|
|
|
/* into */ combinedTypeArgs, implicitTypeArgsCount,
|
|
|
|
/* count */ explicitTypeArgsCount);
|
|
|
|
|
|
|
|
var newMethod = new RuntimeMethodInfo(JavaMethod, -1, reflectedType,
|
|
|
|
originalName, strippedName);
|
|
|
|
newMethod.typeArguments = combinedTypeArgs;
|
|
|
|
newMethod.genericFlags = flgGenericMethod;
|
|
|
|
|
|
|
|
for (int i = 0; i < combinedTypeArgsCount; i++)
|
|
|
|
{
|
|
|
|
var arg = combinedTypeArgs[i] as RuntimeType;
|
|
|
|
if (arg == null)
|
|
|
|
throw new ArgumentNullException();
|
|
|
|
if (arg.IsGenericParameter || arg.ContainsGenericParameters)
|
|
|
|
newMethod.genericFlags |= flgContainsGenericParameters;
|
|
|
|
}
|
|
|
|
|
|
|
|
return newMethod;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Invoke
|
|
|
|
//
|
|
|
|
|
|
|
|
public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder,
|
|
|
|
object[] parameters, CultureInfo culture)
|
|
|
|
{
|
|
|
|
if (ContainsGenericParameters)
|
|
|
|
throw new InvalidOperationException();
|
|
|
|
if (invokeAttr != BindingFlags.Default)
|
|
|
|
throw new PlatformNotSupportedException("bad binding flags " + invokeAttr);
|
|
|
|
if (binder != null)
|
|
|
|
throw new PlatformNotSupportedException("non-null binder");
|
|
|
|
if (culture != null)
|
|
|
|
throw new PlatformNotSupportedException("non-null culture");
|
|
|
|
|
|
|
|
// combine the provided parameters and any suffix type arguments
|
|
|
|
// that were previously injected by MakeGenericMethod
|
|
|
|
|
|
|
|
var typeArgs = typeArguments;
|
|
|
|
if (typeArgs == null && (genericFlags & flgCombineGenericArguments) != 0)
|
|
|
|
typeArgs = typeArguments = reflectedType.GetGenericArguments();
|
|
|
|
|
|
|
|
if (typeArgs != null)
|
|
|
|
{
|
|
|
|
if (parameters == null)
|
|
|
|
parameters = typeArgs;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int nParams = parameters.Length;
|
|
|
|
int nTypes = typeArgs.Length;
|
|
|
|
var newParams = new object[nParams + nTypes];
|
|
|
|
java.lang.System.arraycopy(parameters, 0, newParams, 0, nParams);
|
|
|
|
java.lang.System.arraycopy(typeArgs, 0, newParams, nParams, nTypes);
|
|
|
|
parameters = newParams;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int numParameters = (parameters != null) ? parameters.Length : 0;
|
|
|
|
if (JavaMethod.getParameterTypes().Length != numParameters)
|
|
|
|
throw new TargetParameterCountException();
|
|
|
|
|
|
|
|
return JavaMethod.invoke(obj, parameters);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
|
|
|
|
public override bool IsGenericMethod
|
|
|
|
=> (genericFlags & flgGenericMethod) != 0;
|
|
|
|
|
|
|
|
public override bool IsGenericMethodDefinition
|
|
|
|
=> (genericFlags & flgGenericMethodDefinition) != 0;
|
|
|
|
|
|
|
|
public override bool ContainsGenericParameters
|
|
|
|
=> (genericFlags & flgContainsGenericParameters) != 0;
|
|
|
|
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
|
|
|
|
public override Type ReflectedType => reflectedType;
|
|
|
|
|
|
|
|
public override Type DeclaringType
|
|
|
|
=> system.RuntimeType.GetType(JavaMethod.getDeclaringClass());
|
|
|
|
|
|
|
|
public override MethodAttributes Attributes
|
|
|
|
=> throw new PlatformNotSupportedException();
|
|
|
|
|
|
|
|
public override string Name => strippedName;
|
|
|
|
|
2020-08-29 19:53:56 +03:00
|
|
|
public override System.RuntimeMethodHandle MethodHandle
|
2020-08-26 11:23:24 +03:00
|
|
|
=> throw new PlatformNotSupportedException();
|
|
|
|
|
|
|
|
public override ParameterInfo[] GetParameters()
|
|
|
|
=> throw new PlatformNotSupportedException();
|
|
|
|
|
|
|
|
public override MethodInfo GetBaseDefinition()
|
|
|
|
=> throw new PlatformNotSupportedException();
|
|
|
|
|
|
|
|
public override MethodImplAttributes GetMethodImplementationFlags()
|
|
|
|
=> throw new PlatformNotSupportedException();
|
|
|
|
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
|
|
|
|
public override string ToString() => strippedName;
|
|
|
|
|
|
|
|
//
|
|
|
|
// custom attributes
|
|
|
|
//
|
|
|
|
|
|
|
|
public override bool IsDefined(Type attributeType, bool inherit)
|
|
|
|
=> throw new PlatformNotSupportedException();
|
|
|
|
|
|
|
|
public override object[] GetCustomAttributes(bool inherit)
|
|
|
|
=> throw new PlatformNotSupportedException();
|
|
|
|
|
|
|
|
public override object[] GetCustomAttributes(Type attributeType, bool inherit)
|
|
|
|
=> throw new PlatformNotSupportedException();
|
|
|
|
|
|
|
|
public override ICustomAttributeProvider ReturnTypeCustomAttributes
|
|
|
|
=> throw new PlatformNotSupportedException();
|
|
|
|
|
|
|
|
//
|
|
|
|
// ISerializable
|
|
|
|
//
|
|
|
|
|
|
|
|
public void GetObjectData(SerializationInfo info, StreamingContext context)
|
|
|
|
=> throw new PlatformNotSupportedException();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// declaration of java.lang.reflect.Method and java.lang.reflect.Constructor.
|
|
|
|
// this is needed because java 1.8 inserts a new java.lang.reflect.Executable
|
|
|
|
// class as the base class for Method and Constructor.
|
|
|
|
// this causes an error on Android, because the Executable class is missing.
|
|
|
|
//
|
|
|
|
|
|
|
|
namespace java.lang.reflect
|
|
|
|
{
|
|
|
|
[java.attr.Discard] // discard in output
|
|
|
|
public abstract class Constructor : AccessibleObject
|
|
|
|
{
|
|
|
|
public abstract object newInstance(object[] initargs);
|
|
|
|
public abstract Class[] getParameterTypes();
|
|
|
|
public abstract int getModifiers();
|
|
|
|
}
|
|
|
|
|
|
|
|
[java.attr.Discard] // discard in output
|
|
|
|
public abstract class Method : AccessibleObject
|
|
|
|
{
|
|
|
|
public abstract Class getDeclaringClass();
|
|
|
|
public abstract string getName();
|
|
|
|
public abstract Class[] getParameterTypes();
|
|
|
|
public abstract Class getReturnType();
|
|
|
|
public abstract int getModifiers();
|
|
|
|
public abstract object invoke(object obj, object[] args);
|
|
|
|
}
|
|
|
|
}
|