Skip to content

Commit 16c310e

Browse files
Avoid allocations in CanWrap... methods
1 parent 0548969 commit 16c310e

File tree

1 file changed

+36
-24
lines changed

1 file changed

+36
-24
lines changed

StyleCop.Analyzers/StyleCop.Analyzers/Lightup/LightupHelpers.cs

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -65,18 +65,22 @@ internal static bool CanWrapObject(object obj, Type underlyingType)
6565
return false;
6666
}
6767

68-
ConcurrentDictionary<Type, bool> wrappedObject = SupportedObjectWrappers.GetOrAdd(underlyingType, _ => new ConcurrentDictionary<Type, bool>());
69-
7068
// Avoid creating the delegate if the value already exists
71-
bool canCast;
72-
if (!wrappedObject.TryGetValue(obj.GetType(), out canCast))
69+
if (!SupportedObjectWrappers.TryGetValue(underlyingType, out var wrappedObject))
7370
{
74-
canCast = wrappedObject.GetOrAdd(
75-
obj.GetType(),
76-
kind => underlyingType.GetTypeInfo().IsAssignableFrom(obj.GetType().GetTypeInfo()));
71+
wrappedObject = SupportedObjectWrappers.GetOrAdd(underlyingType, static _ => new ConcurrentDictionary<Type, bool>());
7772
}
7873

79-
return canCast;
74+
// Avoid creating the delegate and capture class if the value already exists
75+
return wrappedObject.TryGetValue(obj.GetType(), out var canCast)
76+
? canCast
77+
: GetOrAdd(obj, underlyingType, wrappedObject);
78+
79+
// Don't inline this method. Otherwise a capture class is generated on each call to CanWrapObject.
80+
static bool GetOrAdd(object obj, Type underlyingType, ConcurrentDictionary<Type, bool> wrappedObject)
81+
=> wrappedObject.GetOrAdd(
82+
obj.GetType(),
83+
kind => underlyingType.GetTypeInfo().IsAssignableFrom(obj.GetType().GetTypeInfo()));
8084
}
8185

8286
internal static bool CanWrapNode(SyntaxNode node, Type underlyingType)
@@ -93,18 +97,22 @@ internal static bool CanWrapNode(SyntaxNode node, Type underlyingType)
9397
return false;
9498
}
9599

96-
ConcurrentDictionary<SyntaxKind, bool> wrappedSyntax = SupportedSyntaxWrappers.GetOrAdd(underlyingType, _ => new ConcurrentDictionary<SyntaxKind, bool>());
97-
98100
// Avoid creating the delegate if the value already exists
99-
bool canCast;
100-
if (!wrappedSyntax.TryGetValue(node.Kind(), out canCast))
101+
if (!SupportedSyntaxWrappers.TryGetValue(underlyingType, out var wrappedSyntax))
101102
{
102-
canCast = wrappedSyntax.GetOrAdd(
103-
node.Kind(),
104-
kind => underlyingType.GetTypeInfo().IsAssignableFrom(node.GetType().GetTypeInfo()));
103+
wrappedSyntax = SupportedSyntaxWrappers.GetOrAdd(underlyingType, static _ => new ConcurrentDictionary<SyntaxKind, bool>());
105104
}
106105

107-
return canCast;
106+
// Avoid creating the delegate and capture class if the value already exists
107+
return wrappedSyntax.TryGetValue(node.Kind(), out var canCast)
108+
? canCast
109+
: GetOrAdd(node, underlyingType, wrappedSyntax);
110+
111+
// Don't inline this method. Otherwise a capture class is generated on each call to CanWrapNode.
112+
static bool GetOrAdd(SyntaxNode node, Type underlyingType, ConcurrentDictionary<SyntaxKind, bool> wrappedSyntax) =>
113+
wrappedSyntax.GetOrAdd(
114+
node.Kind(),
115+
kind => underlyingType.GetTypeInfo().IsAssignableFrom(node.GetType().GetTypeInfo()));
108116
}
109117

110118
internal static bool CanWrapOperation(IOperation operation, Type underlyingType)
@@ -121,18 +129,22 @@ internal static bool CanWrapOperation(IOperation operation, Type underlyingType)
121129
return false;
122130
}
123131

124-
ConcurrentDictionary<OperationKind, bool> wrappedSyntax = SupportedOperationWrappers.GetOrAdd(underlyingType, _ => new ConcurrentDictionary<OperationKind, bool>());
125-
126132
// Avoid creating the delegate if the value already exists
127-
bool canCast;
128-
if (!wrappedSyntax.TryGetValue(operation.Kind, out canCast))
133+
if (!SupportedOperationWrappers.TryGetValue(underlyingType, out var wrappedSyntax))
129134
{
130-
canCast = wrappedSyntax.GetOrAdd(
131-
operation.Kind,
132-
kind => underlyingType.GetTypeInfo().IsAssignableFrom(operation.GetType().GetTypeInfo()));
135+
wrappedSyntax = SupportedOperationWrappers.GetOrAdd(underlyingType, static _ => new ConcurrentDictionary<OperationKind, bool>());
133136
}
134137

135-
return canCast;
138+
// Avoid creating the delegate if the value already exists
139+
return wrappedSyntax.TryGetValue(operation.Kind, out var canCast)
140+
? canCast
141+
: GetOrAdd(operation, underlyingType, wrappedSyntax);
142+
143+
// Don't inline this method. Otherwise a capture class is generated on each call to CanWrapOperation.
144+
static bool GetOrAdd(IOperation operation, Type underlyingType, ConcurrentDictionary<OperationKind, bool> wrappedSyntax) =>
145+
wrappedSyntax.GetOrAdd(
146+
operation.Kind,
147+
kind => underlyingType.GetTypeInfo().IsAssignableFrom(operation.GetType().GetTypeInfo()));
136148
}
137149

138150
internal static Func<TOperation, TProperty> CreateOperationPropertyAccessor<TOperation, TProperty>(Type type, string propertyName)

0 commit comments

Comments
 (0)