forked from microsoft/CsWinRT
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTypeExtensions.cs
More file actions
192 lines (172 loc) · 7.81 KB
/
TypeExtensions.cs
File metadata and controls
192 lines (172 loc) · 7.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
using System.Collections.Concurrent;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
namespace WinRT
{
#if EMBED
internal
#else
public
#endif
static class TypeExtensions
{
private readonly static ConcurrentDictionary<Type, Type> HelperTypeCache = new ConcurrentDictionary<Type, Type>();
#if NET
[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods |
DynamicallyAccessedMemberTypes.NonPublicMethods |
DynamicallyAccessedMemberTypes.PublicNestedTypes |
DynamicallyAccessedMemberTypes.PublicFields)]
#endif
public static Type FindHelperType(this Type type)
{
return HelperTypeCache.GetOrAdd(type,
#if NET
[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods |
DynamicallyAccessedMemberTypes.NonPublicMethods |
DynamicallyAccessedMemberTypes.PublicNestedTypes |
DynamicallyAccessedMemberTypes.PublicFields)]
#endif
(type) =>
{
if (typeof(Exception).IsAssignableFrom(type))
{
type = typeof(Exception);
}
Type customMapping = Projections.FindCustomHelperTypeMapping(type);
if (customMapping is not null)
{
return customMapping;
}
var helperTypeAtribute = type.GetCustomAttribute<WindowsRuntimeHelperTypeAttribute>();
if (helperTypeAtribute is not null)
{
return GetHelperTypeFromAttribute(helperTypeAtribute, type);
}
return FindHelperTypeFallback(type);
});
#if NET
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
Justification = "No members of the generic type are dynamically accessed other than for the attributes on it.")]
[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.PublicFields)]
#endif
static Type GetHelperTypeFromAttribute(WindowsRuntimeHelperTypeAttribute helperTypeAtribute, Type type)
{
if (type.IsGenericType)
{
return helperTypeAtribute.HelperType.MakeGenericType(type.GetGenericArguments());
}
else
{
return helperTypeAtribute.HelperType;
}
}
#if NET
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
Justification = "This is a fallback for compat purposes with existing projections. " +
"Applications which make use of trimming will make use of updated projections that won't hit this code path.")]
#endif
static Type FindHelperTypeFallback(Type type)
{
string fullTypeName = type.FullName;
string ccwTypePrefix = "ABI.Impl.";
if (fullTypeName.StartsWith(ccwTypePrefix, StringComparison.Ordinal))
{
fullTypeName = fullTypeName.Substring(ccwTypePrefix.Length);
}
var helper = $"ABI.{fullTypeName}";
return type.Assembly.GetType(helper) ?? Type.GetType(helper);
}
}
#if NET
[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods |
DynamicallyAccessedMemberTypes.NonPublicMethods |
DynamicallyAccessedMemberTypes.PublicNestedTypes |
DynamicallyAccessedMemberTypes.PublicFields)]
#endif
public static Type GetHelperType(this Type type)
{
var helperType = type.FindHelperType();
if (helperType is object)
return helperType;
throw new InvalidOperationException($"Target type is not a projected type: {type.FullName}.");
}
#if NET
[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)]
#endif
public static Type GetGuidType(this Type type)
{
return type.IsDelegate() ? type.GetHelperType() : type;
}
#if NET
[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicConstructors | DynamicallyAccessedMemberTypes.PublicFields)]
#endif
public static Type FindVftblType(
#if NET
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicNestedTypes)]
#endif
this Type helperType)
{
Type vftblType = helperType.GetNestedType("Vftbl");
if (vftblType is null)
{
return null;
}
if (helperType.IsGenericType && vftblType is object)
{
vftblType = vftblType.MakeGenericType(helperType.GetGenericArguments());
}
return vftblType;
}
internal static IntPtr GetAbiToProjectionVftblPtr(
#if NET
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)]
#endif
this Type helperType)
{
return (IntPtr)(helperType.FindVftblType() ?? helperType).GetField("AbiToProjectionVftablePtr", BindingFlags.Public | BindingFlags.Static).GetValue(null);
}
public static Type GetAbiType(this Type type)
{
return type.GetHelperType().GetMethod("GetAbi", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static).ReturnType;
}
public static Type GetMarshalerType(this Type type)
{
return type.GetHelperType().GetMethod("CreateMarshaler", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static).ReturnType;
}
internal static Type GetMarshaler2Type(this Type type)
{
var helperType = type.GetHelperType();
var createMarshaler = helperType.GetMethod("CreateMarshaler2", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static) ??
helperType.GetMethod("CreateMarshaler", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
return createMarshaler.ReturnType;
}
internal static Type GetMarshalerArrayType(this Type type)
{
return type.GetHelperType().GetMethod("CreateMarshalerArray", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)?.ReturnType;
}
public static bool IsDelegate(this Type type)
{
return typeof(Delegate).IsAssignableFrom(type);
}
internal static bool IsTypeOfType(this Type type)
{
return typeof(Type).IsAssignableFrom(type);
}
public static Type GetRuntimeClassCCWType(this Type type)
{
return type.IsClass && !type.IsArray ? type.GetAuthoringMetadataType() : null;
}
private readonly static ConcurrentDictionary<Type, Type> AuthoringMetadataTypeCache = new ConcurrentDictionary<Type, Type>();
internal static Type GetAuthoringMetadataType(this Type type)
{
return AuthoringMetadataTypeCache.GetOrAdd(type, (type) =>
{
var ccwTypeName = $"ABI.Impl.{type.FullName}";
return type.Assembly.GetType(ccwTypeName, false);
});
}
}
}