forked from ClearFoundry/ClearScript
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCustomAttributes.cs
More file actions
154 lines (123 loc) · 4.56 KB
/
CustomAttributes.cs
File metadata and controls
154 lines (123 loc) · 4.56 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
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using System;
using System.Collections.Generic;
using System.Reflection;
using Microsoft.ClearScript.Util;
namespace Microsoft.ClearScript
{
internal static partial class CustomAttributes
{
private static readonly object cacheLock = new object();
public static T[] GetOrLoad<T>(ICustomAttributeProvider resource, bool inherit) where T : Attribute
{
lock (cacheLock)
{
return GetOrLoad<T>(cache.GetOrCreateValue(resource), resource, inherit);
}
}
public static bool Has<T>(ICustomAttributeProvider resource, bool inherit) where T : Attribute
{
lock (cacheLock)
{
return Has<T>(cache.GetOrCreateValue(resource), resource, inherit);
}
}
private static T[] GetOrLoad<T>(CacheEntry entry, ICustomAttributeProvider resource, bool inherit) where T : Attribute
{
if (entry.TryGet<T>(out var attrs))
{
return attrs;
}
attrs = GetOrLoad<T>(GetIsBypass(entry, resource), resource, inherit);
entry.Add(attrs);
return attrs;
}
private static bool Has<T>(CacheEntry entry, ICustomAttributeProvider resource, bool inherit) where T : Attribute
{
return GetOrLoad<T>(entry, resource, inherit).Length > 0;
}
private static T[] GetOrLoad<T>(bool isBypass, ICustomAttributeProvider resource, bool inherit) where T : Attribute
{
var loader = isBypass ? HostSettings.DefaultCustomAttributeLoader : HostSettings.CustomAttributeLoader;
return loader.LoadCustomAttributes<T>(resource, inherit) ?? ArrayHelpers.GetEmptyArray<T>();
}
private static bool Has<T>(bool isBypass, ICustomAttributeProvider resource, bool inherit) where T : Attribute
{
return GetOrLoad<T>(isBypass, resource, inherit).Length > 0;
}
private static bool GetIsBypass(ICustomAttributeProvider resource)
{
// ReSharper disable once InconsistentlySynchronizedField
return GetIsBypass(cache.GetOrCreateValue(resource), resource);
}
private static bool GetIsBypass(CacheEntry entry, ICustomAttributeProvider resource)
{
if (!entry.IsBypass.HasValue)
{
entry.IsBypass = GetIsBypassInternal(resource);
}
return entry.IsBypass.Value;
}
private static bool GetIsBypassInternal(ICustomAttributeProvider resource)
{
if (Has<BypassCustomAttributeLoaderAttribute>(true, resource, false))
{
return true;
}
var parent = GetParent(resource);
if (parent != null)
{
return GetIsBypass(parent);
}
return false;
}
private static ICustomAttributeProvider GetParent(ICustomAttributeProvider resource)
{
if (resource is ParameterInfo parameter)
{
return parameter.Member;
}
if (resource is Type type)
{
return (type.DeclaringType as ICustomAttributeProvider) ?? type.Module;
}
if (resource is MemberInfo member)
{
return member.DeclaringType;
}
if (resource is Module module)
{
return module.Assembly;
}
return null;
}
#region Nested type: CacheEntry
// ReSharper disable ClassNeverInstantiated.Local
private sealed class CacheEntry
{
private readonly Dictionary<Type, object> map = new Dictionary<Type, object>();
public bool? IsBypass { get; set; }
public void Add<T>(T[] attrs)
{
map.Add(typeof(T), attrs);
}
public bool TryGet<T>(out T[] attrs)
{
if (map.TryGetValue(typeof(T), out var attrsObject))
{
attrs = attrsObject as T[];
return true;
}
attrs = null;
return false;
}
}
// ReSharper restore ClassNeverInstantiated.Local
#endregion
}
[AttributeUsage(AttributeTargets.All, Inherited = false)]
internal sealed class BypassCustomAttributeLoaderAttribute : Attribute
{
}
}