1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System;
6 using System.Text;
7 using System.Reflection;
8 using System.Diagnostics;
9 using System.Collections.Generic;
10 using System.Reflection.Runtime.General;
11 using System.Reflection.Runtime.TypeInfos;
12 using System.Reflection.Runtime.ParameterInfos;
13 
14 using Internal.Reflection.Core;
15 using Internal.Reflection.Core.Execution;
16 
17 namespace System.Reflection.Runtime.MethodInfos
18 {
19     internal static class RuntimeMethodHelpers
20     {
21         //
22         // Returns the ParameterInfo objects for the method parameters and return parameter.
23         //
24         // The ParameterInfo objects will report "contextMethod" as their Member property and use it to get type variable information from
25         // the contextMethod's declaring type. The actual metadata, however, comes from "this."
26         //
27         // The methodTypeArguments provides the fill-ins for any method type variable elements in the parameter type signatures.
28         //
29         // Does not array-copy.
30         //
31         internal static RuntimeParameterInfo[] GetRuntimeParameters<TRuntimeMethodCommon>(ref TRuntimeMethodCommon runtimeMethodCommon, MethodBase contextMethod, RuntimeTypeInfo[] methodTypeArguments, out RuntimeParameterInfo returnParameter)
32             where TRuntimeMethodCommon : IRuntimeMethodCommon<TRuntimeMethodCommon>, IEquatable<TRuntimeMethodCommon>
33         {
34             TypeContext typeContext = contextMethod.DeclaringType.CastToRuntimeTypeInfo().TypeContext;
35             typeContext = new TypeContext(typeContext.GenericTypeArguments, methodTypeArguments);
36             QSignatureTypeHandle[] typeSignatures = runtimeMethodCommon.QualifiedMethodSignature;
37             int count = typeSignatures.Length;
38 
39             VirtualRuntimeParameterInfoArray result = new VirtualRuntimeParameterInfoArray(count);
40             runtimeMethodCommon.FillInMetadataDescribedParameters(ref result, typeSignatures, contextMethod, typeContext);
41 
42             for (int i = 0; i < count; i++)
43             {
44                 if (result[i] == null)
45                 {
46                     result[i] =
47                         RuntimeThinMethodParameterInfo.GetRuntimeThinMethodParameterInfo(
48                             contextMethod,
49                             i - 1,
50                             typeSignatures[i],
51                             typeContext);
52                 }
53             }
54 
55             returnParameter = result.First;
56             return result.Remainder;
57         }
58 
59         // Compute the ToString() value in a pay-to-play-safe way.
60         internal static string ComputeToString<TRuntimeMethodCommon>(ref TRuntimeMethodCommon runtimeMethodCommon, MethodBase contextMethod, RuntimeTypeInfo[] methodTypeArguments)
61             where TRuntimeMethodCommon : IRuntimeMethodCommon<TRuntimeMethodCommon>, IEquatable<TRuntimeMethodCommon>
62         {
63             RuntimeParameterInfo returnParameter;
64             RuntimeParameterInfo[] parameters = GetRuntimeParameters(ref runtimeMethodCommon, contextMethod, methodTypeArguments, out returnParameter);
65             return ComputeToString(contextMethod, methodTypeArguments, parameters, returnParameter);
66         }
67 
68         // Used by method and property ToString() methods to display the list of parameter types. Replicates the behavior of MethodBase.ConstructParameters()
69         // but in a pay-to-play-safe way.
ComputeParametersString(RuntimeParameterInfo[] parameters)70         internal static String ComputeParametersString(RuntimeParameterInfo[] parameters)
71         {
72             StringBuilder sb = new StringBuilder(30);
73             for (int i = 0; i < parameters.Length; i++)
74             {
75                 if (i != 0)
76                     sb.Append(", ");
77                 String parameterTypeString = parameters[i].ParameterTypeString;
78 
79                 // Legacy: Why use "ByRef" for by ref parameters? What language is this?
80                 // VB uses "ByRef" but it should precede (not follow) the parameter name.
81                 // Why don't we just use "&"?
82                 if (parameterTypeString.EndsWith("&"))
83                     parameterTypeString = parameterTypeString.Substring(0, parameterTypeString.Length - 1) + " ByRef";
84                 sb.Append(parameterTypeString);
85             }
86             return sb.ToString();
87         }
88 
ComputeToString(MethodBase contextMethod, RuntimeTypeInfo[] methodTypeArguments, RuntimeParameterInfo[] parameters, RuntimeParameterInfo returnParameter)89         internal static String ComputeToString(MethodBase contextMethod, RuntimeTypeInfo[] methodTypeArguments, RuntimeParameterInfo[] parameters, RuntimeParameterInfo returnParameter)
90         {
91             StringBuilder sb = new StringBuilder(30);
92             sb.Append(returnParameter == null ? "Void" : returnParameter.ParameterTypeString);  // ConstructorInfos allowed to pass in null rather than craft a ReturnParameterInfo that's always of type void.
93             sb.Append(' ');
94             sb.Append(contextMethod.Name);
95             if (methodTypeArguments.Length != 0)
96             {
97                 String sep = "";
98                 sb.Append('[');
99                 foreach (RuntimeTypeInfo methodTypeArgument in methodTypeArguments)
100                 {
101                     sb.Append(sep);
102                     sep = ",";
103                     String name = methodTypeArgument.InternalNameIfAvailable;
104                     if (name == null)
105                         name = Type.DefaultTypeNameWhenMissingMetadata;
106                     sb.Append(methodTypeArgument.Name);
107                 }
108                 sb.Append(']');
109             }
110             sb.Append('(');
111             sb.Append(ComputeParametersString(parameters));
112             sb.Append(')');
113 
114             return sb.ToString();
115         }
116     }
117 }
118