652 lines
29 KiB
C#
652 lines
29 KiB
C#
/*
|
|
Copyright (C) 2014-2019 de4dot@gmail.com
|
|
|
|
This file is part of dnSpy
|
|
|
|
dnSpy is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
dnSpy is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with dnSpy. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
using System;
|
|
using System.Collections.ObjectModel;
|
|
using System.Diagnostics;
|
|
using System.Linq;
|
|
using System.Runtime.InteropServices;
|
|
|
|
namespace dnSpy.Debugger.DotNet.Metadata {
|
|
static class CustomAttributesHelper {
|
|
public static bool IsDefined(ReadOnlyCollection<DmdCustomAttributeData> customAttributes, string attributeTypeFullName) {
|
|
for (int i = 0; i < customAttributes.Count; i++) {
|
|
if (customAttributes[i].AttributeType.FullName == attributeTypeFullName)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static bool IsDefined(ReadOnlyCollection<DmdCustomAttributeData> customAttributes, DmdType? attributeType) {
|
|
for (int i = 0; i < customAttributes.Count; i++) {
|
|
if (DmdMemberInfoEqualityComparer.DefaultType.Equals(customAttributes[i].AttributeType, attributeType))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static bool IsDefined(DmdType type, string attributeTypeFullName, bool inherit) {
|
|
for (DmdType? currentType = type; currentType is not null; currentType = currentType.BaseType) {
|
|
var customAttributes = currentType.GetCustomAttributesData();
|
|
for (int i = 0; i < customAttributes.Count; i++) {
|
|
var ca = customAttributes[i];
|
|
if ((object)currentType != type && ca.IsPseudoCustomAttribute)
|
|
continue;
|
|
if (ca.AttributeType.FullName == attributeTypeFullName)
|
|
return true;
|
|
}
|
|
if (!inherit)
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static bool IsDefined(DmdType type, DmdType? attributeType, bool inherit) {
|
|
for (DmdType? currentType = type; currentType is not null; currentType = currentType.BaseType) {
|
|
var customAttributes = currentType.GetCustomAttributesData();
|
|
for (int i = 0; i < customAttributes.Count; i++) {
|
|
var ca = customAttributes[i];
|
|
if ((object)currentType != type && ca.IsPseudoCustomAttribute)
|
|
continue;
|
|
if (DmdMemberInfoEqualityComparer.DefaultType.Equals(ca.AttributeType, attributeType))
|
|
return true;
|
|
}
|
|
if (!inherit)
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static bool IsDefined(DmdMethodInfo method, string attributeTypeFullName, bool inherit) {
|
|
for (DmdMethodInfo? currentMethod = method; currentMethod is not null; currentMethod = currentMethod.GetParentDefinition()) {
|
|
var customAttributes = currentMethod.GetCustomAttributesData();
|
|
for (int i = 0; i < customAttributes.Count; i++) {
|
|
var ca = customAttributes[i];
|
|
if ((object)currentMethod != method && ca.IsPseudoCustomAttribute)
|
|
continue;
|
|
if (ca.AttributeType.FullName == attributeTypeFullName)
|
|
return true;
|
|
}
|
|
if (!inherit)
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static bool IsDefined(DmdMethodInfo method, DmdType? attributeType, bool inherit) {
|
|
for (DmdMethodInfo? currentMethod = method; currentMethod is not null; currentMethod = currentMethod.GetParentDefinition()) {
|
|
var customAttributes = currentMethod.GetCustomAttributesData();
|
|
for (int i = 0; i < customAttributes.Count; i++) {
|
|
var ca = customAttributes[i];
|
|
if ((object)currentMethod != method && ca.IsPseudoCustomAttribute)
|
|
continue;
|
|
if (DmdMemberInfoEqualityComparer.DefaultType.Equals(ca.AttributeType, attributeType))
|
|
return true;
|
|
}
|
|
if (!inherit)
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static DmdCustomAttributeData? Find(ReadOnlyCollection<DmdCustomAttributeData> customAttributes, string attributeTypeFullName) {
|
|
for (int i = 0; i < customAttributes.Count; i++) {
|
|
var ca = customAttributes[i];
|
|
if (ca.AttributeType.FullName == attributeTypeFullName)
|
|
return ca;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public static DmdCustomAttributeData? Find(ReadOnlyCollection<DmdCustomAttributeData> customAttributes, DmdType? attributeType) {
|
|
for (int i = 0; i < customAttributes.Count; i++) {
|
|
var ca = customAttributes[i];
|
|
if (DmdMemberInfoEqualityComparer.DefaultType.Equals(ca.AttributeType, attributeType))
|
|
return ca;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public static DmdCustomAttributeData? Find(DmdType type, string attributeTypeFullName, bool inherit) {
|
|
for (DmdType? currentType = type; currentType is not null; currentType = currentType.BaseType) {
|
|
var customAttributes = currentType.GetCustomAttributesData();
|
|
for (int i = 0; i < customAttributes.Count; i++) {
|
|
var ca = customAttributes[i];
|
|
if ((object)currentType != type && ca.IsPseudoCustomAttribute)
|
|
continue;
|
|
if (ca.AttributeType.FullName == attributeTypeFullName)
|
|
return ca;
|
|
}
|
|
if (!inherit)
|
|
break;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public static DmdCustomAttributeData? Find(DmdType type, DmdType? attributeType, bool inherit) {
|
|
for (DmdType? currentType = type; currentType is not null; currentType = currentType.BaseType) {
|
|
var customAttributes = currentType.GetCustomAttributesData();
|
|
for (int i = 0; i < customAttributes.Count; i++) {
|
|
var ca = customAttributes[i];
|
|
if ((object)currentType != type && ca.IsPseudoCustomAttribute)
|
|
continue;
|
|
if (DmdMemberInfoEqualityComparer.DefaultType.Equals(ca.AttributeType, attributeType))
|
|
return ca;
|
|
}
|
|
if (!inherit)
|
|
break;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public static DmdCustomAttributeData? Find(DmdMethodInfo method, string attributeTypeFullName, bool inherit) {
|
|
for (DmdMethodInfo? currentMethod = method; currentMethod is not null; currentMethod = currentMethod.GetParentDefinition()) {
|
|
var customAttributes = currentMethod.GetCustomAttributesData();
|
|
for (int i = 0; i < customAttributes.Count; i++) {
|
|
var ca = customAttributes[i];
|
|
if ((object)currentMethod != method && ca.IsPseudoCustomAttribute)
|
|
continue;
|
|
if (ca.AttributeType.FullName == attributeTypeFullName)
|
|
return ca;
|
|
}
|
|
if (!inherit)
|
|
break;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public static DmdCustomAttributeData? Find(DmdMethodInfo method, DmdType? attributeType, bool inherit) {
|
|
for (DmdMethodInfo? currentMethod = method; currentMethod is not null; currentMethod = currentMethod.GetParentDefinition()) {
|
|
var customAttributes = currentMethod.GetCustomAttributesData();
|
|
for (int i = 0; i < customAttributes.Count; i++) {
|
|
var ca = customAttributes[i];
|
|
if ((object)currentMethod != method && ca.IsPseudoCustomAttribute)
|
|
continue;
|
|
if (DmdMemberInfoEqualityComparer.DefaultType.Equals(ca.AttributeType, attributeType))
|
|
return ca;
|
|
}
|
|
if (!inherit)
|
|
break;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
readonly struct SecurityAttributeInfo {
|
|
public int Count { get; }
|
|
|
|
public SecurityAttributeInfo(ReadOnlyCollection<DmdCustomAttributeData> securityAttributes) => Count = securityAttributes.Count;
|
|
|
|
public void CopyTo(DmdCustomAttributeData[] destination, ref int index, ReadOnlyCollection<DmdCustomAttributeData> securityAttributes) {
|
|
if (Count == 0)
|
|
return;
|
|
for (int i = 0; i < securityAttributes.Count; i++) {
|
|
var sa = securityAttributes[i];
|
|
// Reflection uses the first public constructor it finds and uses empty ctor args and named args
|
|
var ctor = sa.AttributeType.GetConstructors().FirstOrDefault() ?? sa.Constructor;
|
|
destination[index++] = new DmdCustomAttributeData(ctor, null, null, isPseudoCustomAttribute: true);
|
|
}
|
|
}
|
|
}
|
|
|
|
readonly struct SerializableAttributeInfo {
|
|
public int Count => ctor is not null ? 1 : 0;
|
|
readonly DmdConstructorInfo? ctor;
|
|
|
|
public SerializableAttributeInfo(DmdType type) {
|
|
if ((type.Attributes & DmdTypeAttributes.Serializable) != 0) {
|
|
var caType = type.AppDomain.GetWellKnownType(DmdWellKnownType.System_SerializableAttribute, isOptional: true);
|
|
ctor = caType?.GetConstructor(Array.Empty<DmdType>());
|
|
Debug2.Assert(caType is null || ctor is not null);
|
|
}
|
|
else
|
|
ctor = null;
|
|
}
|
|
|
|
public void CopyTo(DmdCustomAttributeData[] destination, ref int index) {
|
|
if (Count == 0)
|
|
return;
|
|
destination[index++] = new DmdCustomAttributeData(ctor!, null, null, isPseudoCustomAttribute: true);
|
|
}
|
|
}
|
|
|
|
readonly struct ComImportAttributeInfo {
|
|
public int Count => ctor is not null ? 1 : 0;
|
|
readonly DmdConstructorInfo? ctor;
|
|
|
|
public ComImportAttributeInfo(DmdType type) {
|
|
if (type.IsImport) {
|
|
var caType = type.AppDomain.GetWellKnownType(DmdWellKnownType.System_Runtime_InteropServices_ComImportAttribute, isOptional: true);
|
|
ctor = caType?.GetConstructor(Array.Empty<DmdType>());
|
|
Debug2.Assert(caType is null || ctor is not null);
|
|
}
|
|
else
|
|
ctor = null;
|
|
}
|
|
|
|
public void CopyTo(DmdCustomAttributeData[] destination, ref int index) {
|
|
if (Count == 0)
|
|
return;
|
|
destination[index++] = new DmdCustomAttributeData(ctor!, null, null, isPseudoCustomAttribute: true);
|
|
}
|
|
}
|
|
|
|
readonly struct MarshalAsAttributeInfo {
|
|
public int Count => ctor is not null ? 1 : 0;
|
|
readonly DmdConstructorInfo? ctor;
|
|
|
|
public MarshalAsAttributeInfo(DmdFieldInfo field, DmdMarshalType? marshalType) => ctor = Initialize(field.AppDomain, marshalType);
|
|
public MarshalAsAttributeInfo(DmdParameterInfo parameter, DmdMarshalType? marshalType) => ctor = Initialize(parameter.Member.AppDomain, marshalType);
|
|
|
|
static DmdConstructorInfo? Initialize(DmdAppDomain appDomain, DmdMarshalType? marshalType) {
|
|
if (marshalType is null)
|
|
return null;
|
|
var caType = appDomain.GetWellKnownType(DmdWellKnownType.System_Runtime_InteropServices_MarshalAsAttribute, isOptional: true);
|
|
var unmanagedTypeType = appDomain.GetWellKnownType(DmdWellKnownType.System_Runtime_InteropServices_UnmanagedType, isOptional: true);
|
|
var varEnumType = appDomain.GetWellKnownType(DmdWellKnownType.System_Runtime_InteropServices_VarEnum, isOptional: true);
|
|
if (caType is null || unmanagedTypeType is null || varEnumType is null)
|
|
return null;
|
|
var ctor = caType.GetConstructor(new[] { unmanagedTypeType });
|
|
Debug2.Assert(ctor is not null);
|
|
return ctor;
|
|
}
|
|
|
|
public void CopyTo(DmdCustomAttributeData[] destination, ref int index, DmdMarshalType? marshalType) {
|
|
if (Count == 0)
|
|
return;
|
|
int argsCount = 5;
|
|
if (marshalType!.MarshalType is not null)
|
|
argsCount++;
|
|
if (marshalType.MarshalTypeRef is not null)
|
|
argsCount++;
|
|
if (marshalType.MarshalCookie is not null)
|
|
argsCount++;
|
|
if (marshalType.SafeArrayUserDefinedSubType is not null)
|
|
argsCount++;
|
|
var type = ctor!.ReflectedType!;
|
|
var appDomain = type.AppDomain;
|
|
var unmanagedTypeType = appDomain.GetWellKnownType(DmdWellKnownType.System_Runtime_InteropServices_UnmanagedType);
|
|
var varEnumType = appDomain.GetWellKnownType(DmdWellKnownType.System_Runtime_InteropServices_VarEnum);
|
|
var namedArgs = new DmdCustomAttributeNamedArgument[argsCount];
|
|
int w = 0;
|
|
namedArgs[w++] = new DmdCustomAttributeNamedArgument(type.GetField("ArraySubType"), new DmdCustomAttributeTypedArgument(unmanagedTypeType, (int)marshalType.ArraySubType));
|
|
namedArgs[w++] = new DmdCustomAttributeNamedArgument(type.GetField("SizeParamIndex"), new DmdCustomAttributeTypedArgument(appDomain.System_Int16, marshalType.SizeParamIndex));
|
|
namedArgs[w++] = new DmdCustomAttributeNamedArgument(type.GetField("SizeConst"), new DmdCustomAttributeTypedArgument(appDomain.System_Int32, marshalType.SizeConst));
|
|
namedArgs[w++] = new DmdCustomAttributeNamedArgument(type.GetField("IidParameterIndex"), new DmdCustomAttributeTypedArgument(appDomain.System_Int32, marshalType.IidParameterIndex));
|
|
namedArgs[w++] = new DmdCustomAttributeNamedArgument(type.GetField("SafeArraySubType"), new DmdCustomAttributeTypedArgument(varEnumType, (int)marshalType.SafeArraySubType));
|
|
if (marshalType.MarshalType is not null)
|
|
namedArgs[w++] = new DmdCustomAttributeNamedArgument(type.GetField("MarshalType"), new DmdCustomAttributeTypedArgument(appDomain.System_String, marshalType.MarshalType));
|
|
if (marshalType.MarshalTypeRef is not null)
|
|
namedArgs[w++] = new DmdCustomAttributeNamedArgument(type.GetField("MarshalTypeRef"), new DmdCustomAttributeTypedArgument(appDomain.System_Type, marshalType.MarshalTypeRef));
|
|
if (marshalType.MarshalCookie is not null)
|
|
namedArgs[w++] = new DmdCustomAttributeNamedArgument(type.GetField("MarshalCookie"), new DmdCustomAttributeTypedArgument(appDomain.System_String, marshalType.MarshalCookie));
|
|
if (marshalType.SafeArrayUserDefinedSubType is not null)
|
|
namedArgs[w++] = new DmdCustomAttributeNamedArgument(type.GetField("SafeArrayUserDefinedSubType"), new DmdCustomAttributeTypedArgument(appDomain.System_Type, marshalType.SafeArrayUserDefinedSubType));
|
|
if (namedArgs.Length != w)
|
|
throw new InvalidOperationException();
|
|
var ctorArgs = new[] { new DmdCustomAttributeTypedArgument(unmanagedTypeType, (int)marshalType.Value) };
|
|
destination[index++] = new DmdCustomAttributeData(ctor, ctorArgs, namedArgs, isPseudoCustomAttribute: true);
|
|
}
|
|
}
|
|
|
|
readonly struct FieldOffsetAttributeInfo {
|
|
public int Count => ctor is not null ? 1 : 0;
|
|
readonly DmdConstructorInfo? ctor;
|
|
readonly int offset;
|
|
|
|
public FieldOffsetAttributeInfo(DmdFieldInfo field, uint? offset) {
|
|
if (offset is not null) {
|
|
this.offset = (int)offset.Value;
|
|
var caType = field.AppDomain.GetWellKnownType(DmdWellKnownType.System_Runtime_InteropServices_FieldOffsetAttribute, isOptional: true);
|
|
ctor = caType?.GetConstructor(new[] { field.AppDomain.System_Int32 });
|
|
Debug2.Assert(caType is null || ctor is not null);
|
|
}
|
|
else {
|
|
ctor = null;
|
|
this.offset = 0;
|
|
}
|
|
}
|
|
|
|
public void CopyTo(DmdCustomAttributeData[] destination, ref int index) {
|
|
if (Count == 0)
|
|
return;
|
|
var ctorArgs = new[] { new DmdCustomAttributeTypedArgument(ctor!.AppDomain.System_Int32, offset) };
|
|
destination[index++] = new DmdCustomAttributeData(ctor, ctorArgs, null, isPseudoCustomAttribute: true);
|
|
}
|
|
}
|
|
|
|
readonly struct NonSerializedAttributeInfo {
|
|
public int Count => ctor is not null ? 1 : 0;
|
|
readonly DmdConstructorInfo? ctor;
|
|
|
|
public NonSerializedAttributeInfo(DmdFieldInfo field) {
|
|
if ((field.Attributes & DmdFieldAttributes.NotSerialized) != 0) {
|
|
var caType = field.AppDomain.GetWellKnownType(DmdWellKnownType.System_NonSerializedAttribute, isOptional: true);
|
|
ctor = caType?.GetConstructor(Array.Empty<DmdType>());
|
|
Debug2.Assert(caType is null || ctor is not null);
|
|
}
|
|
else
|
|
ctor = null;
|
|
}
|
|
|
|
public void CopyTo(DmdCustomAttributeData[] destination, ref int index) {
|
|
if (Count == 0)
|
|
return;
|
|
destination[index++] = new DmdCustomAttributeData(ctor!, null, null, isPseudoCustomAttribute: true);
|
|
}
|
|
}
|
|
|
|
readonly struct DllImportAttributeInfo {
|
|
public int Count => ctor is not null ? 1 : 0;
|
|
readonly DmdConstructorInfo? ctor;
|
|
|
|
public DllImportAttributeInfo(DmdMethodInfo method, in DmdImplMap? implMap) {
|
|
if (implMap is not null) {
|
|
var appDomain = method.AppDomain;
|
|
var caType = appDomain.GetWellKnownType(DmdWellKnownType.System_Runtime_InteropServices_DllImportAttribute, isOptional: true);
|
|
var charSetType = appDomain.GetWellKnownType(DmdWellKnownType.System_Runtime_InteropServices_CharSet, isOptional: true);
|
|
var callingConventionType = appDomain.GetWellKnownType(DmdWellKnownType.System_Runtime_InteropServices_CallingConvention, isOptional: true);
|
|
if (charSetType is null || callingConventionType is null || caType is null)
|
|
ctor = null;
|
|
else {
|
|
ctor = caType.GetConstructor(DmdBindingFlags.Public | DmdBindingFlags.NonPublic | DmdBindingFlags.Instance, new[] { appDomain.System_String });
|
|
Debug2.Assert(ctor is not null);
|
|
}
|
|
}
|
|
else
|
|
ctor = null;
|
|
}
|
|
|
|
public void CopyTo(DmdCustomAttributeData[] destination, ref int index, DmdMethodInfo method, in DmdImplMap? implMap) {
|
|
if (Count == 0)
|
|
return;
|
|
|
|
var appDomain = ctor!.AppDomain;
|
|
var im = implMap!.Value;
|
|
var attributes = im.Attributes;
|
|
var charSetType = appDomain.GetWellKnownType(DmdWellKnownType.System_Runtime_InteropServices_CharSet);
|
|
var callingConventionType = appDomain.GetWellKnownType(DmdWellKnownType.System_Runtime_InteropServices_CallingConvention);
|
|
|
|
CharSet charSet;
|
|
switch (attributes & DmdPInvokeAttributes.CharSetMask) {
|
|
default:
|
|
case DmdPInvokeAttributes.CharSetNotSpec: charSet = CharSet.None; break;
|
|
case DmdPInvokeAttributes.CharSetAnsi: charSet = CharSet.Ansi; break;
|
|
case DmdPInvokeAttributes.CharSetUnicode: charSet = CharSet.Unicode; break;
|
|
case DmdPInvokeAttributes.CharSetAuto: charSet = CharSet.Auto; break;
|
|
}
|
|
|
|
CallingConvention callingConvention;
|
|
switch (attributes & DmdPInvokeAttributes.CallConvMask) {
|
|
case DmdPInvokeAttributes.CallConvWinapi: callingConvention = CallingConvention.Winapi; break;
|
|
case DmdPInvokeAttributes.CallConvCdecl: callingConvention = CallingConvention.Cdecl; break;
|
|
case DmdPInvokeAttributes.CallConvStdcall: callingConvention = CallingConvention.StdCall; break;
|
|
case DmdPInvokeAttributes.CallConvThiscall: callingConvention = CallingConvention.ThisCall; break;
|
|
case DmdPInvokeAttributes.CallConvFastcall: callingConvention = CallingConvention.FastCall; break;
|
|
default: callingConvention = CallingConvention.Cdecl; break;
|
|
}
|
|
|
|
var ctorArgs = new[] { new DmdCustomAttributeTypedArgument(appDomain.System_String, im.Module) };
|
|
var type = ctor.ReflectedType!;
|
|
var namedArgs = new DmdCustomAttributeNamedArgument[8] {
|
|
new DmdCustomAttributeNamedArgument(type.GetField("EntryPoint"), new DmdCustomAttributeTypedArgument(appDomain.System_String, im.Name)),
|
|
new DmdCustomAttributeNamedArgument(type.GetField("CharSet"), new DmdCustomAttributeTypedArgument(charSetType, (int)charSet)),
|
|
new DmdCustomAttributeNamedArgument(type.GetField("ExactSpelling"), new DmdCustomAttributeTypedArgument(appDomain.System_Boolean, (attributes & DmdPInvokeAttributes.NoMangle) != 0)),
|
|
new DmdCustomAttributeNamedArgument(type.GetField("SetLastError"), new DmdCustomAttributeTypedArgument(appDomain.System_Boolean, (attributes & DmdPInvokeAttributes.SupportsLastError) != 0)),
|
|
new DmdCustomAttributeNamedArgument(type.GetField("PreserveSig"), new DmdCustomAttributeTypedArgument(appDomain.System_Boolean, method.IsPreserveSig)),
|
|
new DmdCustomAttributeNamedArgument(type.GetField("CallingConvention"), new DmdCustomAttributeTypedArgument(callingConventionType, (int)callingConvention)),
|
|
new DmdCustomAttributeNamedArgument(type.GetField("BestFitMapping"), new DmdCustomAttributeTypedArgument(appDomain.System_Boolean, (attributes & DmdPInvokeAttributes.BestFitMask) == DmdPInvokeAttributes.BestFitEnabled)),
|
|
new DmdCustomAttributeNamedArgument(type.GetField("ThrowOnUnmappableChar"), new DmdCustomAttributeTypedArgument(appDomain.System_Boolean, (attributes & DmdPInvokeAttributes.ThrowOnUnmappableCharMask) == DmdPInvokeAttributes.ThrowOnUnmappableCharEnabled)),
|
|
};
|
|
destination[index++] = new DmdCustomAttributeData(ctor, ctorArgs, namedArgs, isPseudoCustomAttribute: true);
|
|
}
|
|
}
|
|
|
|
readonly struct PreserveSigAttributeInfo {
|
|
public int Count => ctor is not null ? 1 : 0;
|
|
readonly DmdConstructorInfo? ctor;
|
|
|
|
public PreserveSigAttributeInfo(DmdMethodInfo method) {
|
|
if ((method.MethodImplementationFlags & DmdMethodImplAttributes.PreserveSig) != 0) {
|
|
var caType = method.AppDomain.GetWellKnownType(DmdWellKnownType.System_Runtime_InteropServices_PreserveSigAttribute, isOptional: true);
|
|
ctor = caType?.GetConstructor(Array.Empty<DmdType>());
|
|
Debug2.Assert(caType is null || ctor is not null);
|
|
}
|
|
else
|
|
ctor = null;
|
|
}
|
|
|
|
public void CopyTo(DmdCustomAttributeData[] destination, ref int index) {
|
|
if (Count == 0)
|
|
return;
|
|
destination[index++] = new DmdCustomAttributeData(ctor!, null, null, isPseudoCustomAttribute: true);
|
|
}
|
|
}
|
|
|
|
readonly struct InAttributeInfo {
|
|
public int Count => ctor is not null ? 1 : 0;
|
|
readonly DmdConstructorInfo? ctor;
|
|
|
|
public InAttributeInfo(DmdParameterInfo parameter) {
|
|
if (parameter.IsIn) {
|
|
var caType = parameter.Member.AppDomain.GetWellKnownType(DmdWellKnownType.System_Runtime_InteropServices_InAttribute, isOptional: true);
|
|
ctor = caType?.GetConstructor(Array.Empty<DmdType>());
|
|
Debug2.Assert(caType is null || ctor is not null);
|
|
}
|
|
else
|
|
ctor = null;
|
|
}
|
|
|
|
public void CopyTo(DmdCustomAttributeData[] destination, ref int index) {
|
|
if (Count == 0)
|
|
return;
|
|
destination[index++] = new DmdCustomAttributeData(ctor!, null, null, isPseudoCustomAttribute: true);
|
|
}
|
|
}
|
|
|
|
readonly struct OutAttributeInfo {
|
|
public int Count => ctor is not null ? 1 : 0;
|
|
readonly DmdConstructorInfo? ctor;
|
|
|
|
public OutAttributeInfo(DmdParameterInfo parameter) {
|
|
if (parameter.IsOut) {
|
|
var caType = parameter.Member.AppDomain.GetWellKnownType(DmdWellKnownType.System_Runtime_InteropServices_OutAttribute, isOptional: true);
|
|
ctor = caType?.GetConstructor(Array.Empty<DmdType>());
|
|
Debug2.Assert(caType is null || ctor is not null);
|
|
}
|
|
else
|
|
ctor = null;
|
|
}
|
|
|
|
public void CopyTo(DmdCustomAttributeData[] destination, ref int index) {
|
|
if (Count == 0)
|
|
return;
|
|
destination[index++] = new DmdCustomAttributeData(ctor!, null, null, isPseudoCustomAttribute: true);
|
|
}
|
|
}
|
|
|
|
readonly struct OptionalAttributeInfo {
|
|
public int Count => ctor is not null ? 1 : 0;
|
|
readonly DmdConstructorInfo? ctor;
|
|
|
|
public OptionalAttributeInfo(DmdParameterInfo parameter) {
|
|
if (parameter.IsOptional) {
|
|
var caType = parameter.Member.AppDomain.GetWellKnownType(DmdWellKnownType.System_Runtime_InteropServices_OptionalAttribute, isOptional: true);
|
|
ctor = caType?.GetConstructor(Array.Empty<DmdType>());
|
|
Debug2.Assert(caType is null || ctor is not null);
|
|
}
|
|
else
|
|
ctor = null;
|
|
}
|
|
|
|
public void CopyTo(DmdCustomAttributeData[] destination, ref int index) {
|
|
if (Count == 0)
|
|
return;
|
|
destination[index++] = new DmdCustomAttributeData(ctor!, null, null, isPseudoCustomAttribute: true);
|
|
}
|
|
}
|
|
|
|
public static ReadOnlyCollection<DmdCustomAttributeData> AddPseudoCustomAttributes(DmdType type, DmdCustomAttributeData[]? customAttributes, ReadOnlyCollection<DmdCustomAttributeData> securityAttributes) {
|
|
if (customAttributes is null)
|
|
customAttributes = Array.Empty<DmdCustomAttributeData>();
|
|
|
|
var serializableAttributeInfo = new SerializableAttributeInfo(type);
|
|
var comImportAttributeInfo = new ComImportAttributeInfo(type);
|
|
var securityAttributeInfo = new SecurityAttributeInfo(securityAttributes);
|
|
|
|
int pseudoCount = serializableAttributeInfo.Count + comImportAttributeInfo.Count + securityAttributeInfo.Count;
|
|
if (pseudoCount != 0) {
|
|
var cas = new DmdCustomAttributeData[pseudoCount + customAttributes.Length];
|
|
int index = 0;
|
|
serializableAttributeInfo.CopyTo(cas, ref index);
|
|
comImportAttributeInfo.CopyTo(cas, ref index);
|
|
securityAttributeInfo.CopyTo(cas, ref index, securityAttributes);
|
|
if (pseudoCount != index)
|
|
throw new InvalidOperationException();
|
|
Array.Copy(customAttributes, 0, cas, pseudoCount, customAttributes.Length);
|
|
customAttributes = cas;
|
|
}
|
|
|
|
return ReadOnlyCollectionHelpers.Create(customAttributes);
|
|
}
|
|
|
|
public static ReadOnlyCollection<DmdCustomAttributeData> AddPseudoCustomAttributes(DmdFieldInfo field, DmdCustomAttributeData[]? customAttributes, uint? fieldOffset, DmdMarshalType? marshalType) {
|
|
if (customAttributes is null)
|
|
customAttributes = Array.Empty<DmdCustomAttributeData>();
|
|
|
|
var marshalAsAttributeInfo = new MarshalAsAttributeInfo(field, marshalType);
|
|
var fieldOffsetAttributeInfo = new FieldOffsetAttributeInfo(field, fieldOffset);
|
|
var nonSerializedAttributeInfo = new NonSerializedAttributeInfo(field);
|
|
|
|
int pseudoCount = marshalAsAttributeInfo.Count + fieldOffsetAttributeInfo.Count + nonSerializedAttributeInfo.Count;
|
|
if (pseudoCount != 0) {
|
|
var cas = new DmdCustomAttributeData[pseudoCount + customAttributes.Length];
|
|
int index = 0;
|
|
marshalAsAttributeInfo.CopyTo(cas, ref index, marshalType);
|
|
fieldOffsetAttributeInfo.CopyTo(cas, ref index);
|
|
nonSerializedAttributeInfo.CopyTo(cas, ref index);
|
|
if (pseudoCount != index)
|
|
throw new InvalidOperationException();
|
|
Array.Copy(customAttributes, 0, cas, pseudoCount, customAttributes.Length);
|
|
customAttributes = cas;
|
|
}
|
|
|
|
return ReadOnlyCollectionHelpers.Create(customAttributes);
|
|
}
|
|
|
|
public static ReadOnlyCollection<DmdCustomAttributeData> AddPseudoCustomAttributes(DmdConstructorInfo ctor, DmdCustomAttributeData[]? customAttributes, ReadOnlyCollection<DmdCustomAttributeData> securityAttributes) {
|
|
if (customAttributes is null)
|
|
customAttributes = Array.Empty<DmdCustomAttributeData>();
|
|
|
|
var securityAttributeInfo = new SecurityAttributeInfo(securityAttributes);
|
|
|
|
int pseudoCount = securityAttributeInfo.Count;
|
|
if (pseudoCount != 0) {
|
|
var cas = new DmdCustomAttributeData[pseudoCount + customAttributes.Length];
|
|
int index = 0;
|
|
securityAttributeInfo.CopyTo(cas, ref index, securityAttributes);
|
|
if (pseudoCount != index)
|
|
throw new InvalidOperationException();
|
|
Array.Copy(customAttributes, 0, cas, pseudoCount, customAttributes.Length);
|
|
customAttributes = cas;
|
|
}
|
|
|
|
return ReadOnlyCollectionHelpers.Create(customAttributes);
|
|
}
|
|
|
|
public static ReadOnlyCollection<DmdCustomAttributeData> AddPseudoCustomAttributes(DmdMethodInfo method, DmdCustomAttributeData[]? customAttributes, ReadOnlyCollection<DmdCustomAttributeData> securityAttributes, in DmdImplMap? implMap) {
|
|
if (customAttributes is null)
|
|
customAttributes = Array.Empty<DmdCustomAttributeData>();
|
|
|
|
var dllImportAttributeInfo = new DllImportAttributeInfo(method, implMap);
|
|
var preserveSigAttributeInfo = new PreserveSigAttributeInfo(method);
|
|
var securityAttributeInfo = new SecurityAttributeInfo(securityAttributes);
|
|
|
|
int pseudoCount = dllImportAttributeInfo.Count + preserveSigAttributeInfo.Count + securityAttributeInfo.Count;
|
|
if (pseudoCount != 0) {
|
|
var cas = new DmdCustomAttributeData[pseudoCount + customAttributes.Length];
|
|
int index = 0;
|
|
dllImportAttributeInfo.CopyTo(cas, ref index, method, implMap);
|
|
preserveSigAttributeInfo.CopyTo(cas, ref index);
|
|
securityAttributeInfo.CopyTo(cas, ref index, securityAttributes);
|
|
if (pseudoCount != index)
|
|
throw new InvalidOperationException();
|
|
Array.Copy(customAttributes, 0, cas, pseudoCount, customAttributes.Length);
|
|
customAttributes = cas;
|
|
}
|
|
|
|
return ReadOnlyCollectionHelpers.Create(customAttributes);
|
|
}
|
|
|
|
public static ReadOnlyCollection<DmdCustomAttributeData> AddPseudoCustomAttributes(DmdPropertyInfo property, DmdCustomAttributeData[]? customAttributes) =>
|
|
ReadOnlyCollectionHelpers.Create(customAttributes);
|
|
|
|
public static ReadOnlyCollection<DmdCustomAttributeData> AddPseudoCustomAttributes(DmdEventInfo @event, DmdCustomAttributeData[]? customAttributes) =>
|
|
ReadOnlyCollectionHelpers.Create(customAttributes);
|
|
|
|
public static ReadOnlyCollection<DmdCustomAttributeData> AddPseudoCustomAttributes(DmdParameterInfo parameter, DmdCustomAttributeData[]? customAttributes, DmdMarshalType? marshalType) {
|
|
if (customAttributes is null)
|
|
customAttributes = Array.Empty<DmdCustomAttributeData>();
|
|
|
|
var inAttributeInfo = new InAttributeInfo(parameter);
|
|
var outAttributeInfo = new OutAttributeInfo(parameter);
|
|
var optionalAttributeInfo = new OptionalAttributeInfo(parameter);
|
|
var marshalAsAttributeInfo = new MarshalAsAttributeInfo(parameter, marshalType);
|
|
|
|
int pseudoCount = inAttributeInfo.Count + outAttributeInfo.Count + optionalAttributeInfo.Count + marshalAsAttributeInfo.Count;
|
|
if (pseudoCount != 0) {
|
|
var cas = new DmdCustomAttributeData[pseudoCount + customAttributes.Length];
|
|
int index = 0;
|
|
inAttributeInfo.CopyTo(cas, ref index);
|
|
outAttributeInfo.CopyTo(cas, ref index);
|
|
optionalAttributeInfo.CopyTo(cas, ref index);
|
|
marshalAsAttributeInfo.CopyTo(cas, ref index, marshalType);
|
|
if (pseudoCount != index)
|
|
throw new InvalidOperationException();
|
|
Array.Copy(customAttributes, 0, cas, pseudoCount, customAttributes.Length);
|
|
customAttributes = cas;
|
|
}
|
|
|
|
return ReadOnlyCollectionHelpers.Create(customAttributes);
|
|
}
|
|
|
|
public static ReadOnlyCollection<DmdCustomAttributeData> AddPseudoCustomAttributes(DmdAssembly assembly, DmdCustomAttributeData[]? customAttributes, ReadOnlyCollection<DmdCustomAttributeData> securityAttributes) {
|
|
if (customAttributes is null)
|
|
customAttributes = Array.Empty<DmdCustomAttributeData>();
|
|
|
|
var securityAttributeInfo = new SecurityAttributeInfo(securityAttributes);
|
|
|
|
int pseudoCount = securityAttributeInfo.Count;
|
|
if (pseudoCount != 0) {
|
|
var cas = new DmdCustomAttributeData[pseudoCount + customAttributes.Length];
|
|
int index = 0;
|
|
securityAttributeInfo.CopyTo(cas, ref index, securityAttributes);
|
|
if (pseudoCount != index)
|
|
throw new InvalidOperationException();
|
|
Array.Copy(customAttributes, 0, cas, pseudoCount, customAttributes.Length);
|
|
customAttributes = cas;
|
|
}
|
|
|
|
return ReadOnlyCollectionHelpers.Create(customAttributes);
|
|
}
|
|
|
|
public static ReadOnlyCollection<DmdCustomAttributeData> AddPseudoCustomAttributes(DmdModule module, DmdCustomAttributeData[]? customAttributes) =>
|
|
ReadOnlyCollectionHelpers.Create(customAttributes);
|
|
}
|
|
}
|