Skip to content

Commit f60ca98

Browse files
Refactor: Remove ILocks.HasLockField and shift locking responsibility into CompositionCode. Simplify constructor builders by eliminating unnecessary ILocks dependency.
1 parent 61918e1 commit f60ca98

9 files changed

Lines changed: 96 additions & 87 deletions

src/Pure.DI.Core/Core/Code/CompositionBuilder.cs

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,10 @@ public CompositionCode Build(DependencyGraph graph)
153153
}
154154
}
155155
var setupContextMembers = graph.Source.SetupContextMembers;
156+
var setupContextMembersToCopy = GetSetupContextMembersToCopy(setupContextMembers);
157+
var setupContextArgsToCopy = setupContextArgs
158+
.Where(arg => arg.Kind != SetupContextKind.RootArgument)
159+
.ToImmutableArray();
156160

157161
var totalDisposablesCount = 0;
158162
var disposablesCount = 0;
@@ -180,6 +184,17 @@ public CompositionCode Build(DependencyGraph graph)
180184
asyncDisposablesCount++;
181185
}
182186
}
187+
188+
var classArgsToStore = varDeclarationTools.Sort(classArgs).Distinct().ToImmutableArray();
189+
var isLockRequired = isThreadSafe || HasRootOverrides(graph);
190+
var requiresParentScope = singletons.Length > 0
191+
|| classArgsToStore.Length > 0
192+
|| setupContextArgsToCopy.Length > 0
193+
|| setupContextMembersToCopy.Length > 0
194+
|| isLockRequired
195+
|| totalDisposablesCount > 0;
196+
var scopeFactoryName = graph.Source.Hints.ScopeFactoryName;
197+
var isFactoryMethod = requiresParentScope && !string.IsNullOrWhiteSpace(scopeFactoryName);
183198
var composition = new CompositionCode(
184199
graph,
185200
new Lines(),
@@ -191,11 +206,66 @@ public CompositionCode Build(DependencyGraph graph)
191206
isThreadSafe,
192207
new Lines(),
193208
singletons,
194-
varDeclarationTools.Sort(classArgs).Distinct().ToImmutableArray(),
209+
classArgsToStore,
195210
setupContextArgs.ToImmutableArray(),
196-
setupContextMembers);
211+
setupContextMembers,
212+
setupContextArgsToCopy,
213+
setupContextMembersToCopy,
214+
scopeFactoryName,
215+
isFactoryMethod,
216+
requiresParentScope,
217+
isLockRequired);
197218

198219
var diagram = classDiagramBuilder.Build(composition);
199220
return composition with { Diagram = diagram };
200221
}
222+
223+
private bool HasRootOverrides(DependencyGraph graph) =>
224+
graph.Roots.Any(root => overridesRegistry.GetOverrides(root).Any());
225+
226+
private static ImmutableArray<string> GetSetupContextMembersToCopy(ImmutableArray<SetupContextMembers> setupContextMembers)
227+
{
228+
var memberNames = new HashSet<string>(StringComparer.Ordinal);
229+
foreach (var setupContext in setupContextMembers)
230+
{
231+
foreach (var member in setupContext.Members)
232+
{
233+
switch (member)
234+
{
235+
case FieldDeclarationSyntax { Declaration: { } declaration }:
236+
foreach (var variable in declaration.Variables)
237+
{
238+
if (!variable.Identifier.IsKind(SyntaxKind.None))
239+
{
240+
memberNames.Add(variable.Identifier.ValueText);
241+
}
242+
}
243+
244+
break;
245+
246+
case PropertyDeclarationSyntax property when IsPropertyAssignable(property):
247+
if (!property.Identifier.IsKind(SyntaxKind.None))
248+
{
249+
memberNames.Add(property.Identifier.ValueText);
250+
}
251+
252+
break;
253+
}
254+
}
255+
}
256+
257+
return memberNames.ToImmutableArray();
258+
}
259+
260+
private static bool IsPropertyAssignable(PropertyDeclarationSyntax property)
261+
{
262+
if (property.ExpressionBody is not null || property.AccessorList is not { } accessorList)
263+
{
264+
return false;
265+
}
266+
267+
return accessorList.Accessors.Any(accessor =>
268+
accessor.Kind() is SyntaxKind.SetAccessorDeclaration or SyntaxKind.InitAccessorDeclaration)
269+
|| accessorList.Accessors.All(accessor => accessor.Body is null && accessor.ExpressionBody is null);
270+
}
201271
}

src/Pure.DI.Core/Core/Code/ILocks.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,5 @@
22

33
interface ILocks
44
{
5-
bool HasLockField(DependencyGraph dependencyGraph);
6-
75
void AddLockStatements(bool isStatic, Lines lines, bool isAsync);
8-
}
6+
}
Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
// ReSharper disable ClassNeverInstantiated.Global
22
namespace Pure.DI.Core.Code;
33

4-
sealed class Locks(IOverridesRegistry overridesRegistry) : ILocks
4+
sealed class Locks : ILocks
55
{
6-
public bool HasLockField(DependencyGraph dependencyGraph) =>
7-
dependencyGraph.Roots.Any(root => overridesRegistry.GetOverrides(root).Any());
8-
96
public void AddLockStatements(bool isStatic, Lines lines, bool isAsync)
107
{
118
if (isAsync)
@@ -15,4 +12,4 @@ public void AddLockStatements(bool isStatic, Lines lines, bool isAsync)
1512

1613
lines.AppendLine($"lock ({(isStatic ? Names.PerResolveLockFieldName : Names.LockFieldName)})");
1714
}
18-
}
15+
}

src/Pure.DI.Core/Core/Code/Parts/DefaultConstructorBuilder.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
namespace Pure.DI.Core.Code.Parts;
44

55
sealed class DefaultConstructorBuilder(
6-
ILocks locks,
76
IConstructors constructors,
87
ICodeNameProvider codeNameProvider)
98
: IClassPartBuilder
@@ -12,7 +11,7 @@ sealed class DefaultConstructorBuilder(
1211

1312
public CompositionCode Build(CompositionCode composition)
1413
{
15-
if (!constructors.IsEnabled(composition, ConstructorKind.Default) || !string.IsNullOrWhiteSpace(composition.Source.Source.Hints.ScopeFactoryName))
14+
if (!constructors.IsEnabled(composition, ConstructorKind.Default) || composition.IsFactoryMethod)
1615
{
1716
return composition;
1817
}
@@ -38,7 +37,7 @@ public CompositionCode Build(CompositionCode composition)
3837
code.AppendLine($"{Names.RootFieldName} = this;");
3938
}
4039

41-
if (composition.IsLockRequired(locks))
40+
if (composition.IsLockRequired)
4241
{
4342
code.AppendLine(new Line(int.MinValue, "#if NET9_0_OR_GREATER"));
4443
code.AppendLine($"{Names.LockFieldName} = new {Names.LockTypeName}();");

src/Pure.DI.Core/Core/Code/Parts/DisposeMethodBuilder.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ private void AddSyncPart(CompositionCode composition, Lines code, bool isAsync)
186186
{
187187
code.AppendLine("int disposeIndex;");
188188
code.AppendLine("object[] disposables;");
189-
var isLockRequired = composition.IsLockRequired(locks);
189+
var isLockRequired = composition.IsLockRequired;
190190
if (isLockRequired)
191191
{
192192
locks.AddLockStatements(false, code, isAsync);
@@ -218,4 +218,4 @@ private void AddSyncPart(CompositionCode composition, Lines code, bool isAsync)
218218
code.AppendLine(BlockFinish);
219219
}
220220
}
221-
}
221+
}

src/Pure.DI.Core/Core/Code/Parts/FieldsBuilder.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ namespace Pure.DI.Core.Code.Parts;
55

66
sealed class FieldsBuilder(
77
ITypeResolver typeResolver,
8-
ILocks locks,
98
IConstructors constructors)
109
: IClassPartBuilder
1110
{
@@ -18,7 +17,7 @@ public CompositionCode Build(CompositionCode composition)
1817
var compilation = composition.Compilation;
1918
var nullable = compilation.Options.NullableContextOptions == NullableContextOptions.Disable ? "" : "?";
2019
var isAnyConstructorEnabled = constructors.IsEnabled(composition.Source);
21-
var hasScopeFactory = isAnyConstructorEnabled && constructors.IsEnabled(composition, ConstructorKind.Scope) && !string.IsNullOrWhiteSpace(composition.Source.Source.Hints.ScopeFactoryName);
20+
var hasScopeFactory = isAnyConstructorEnabled && constructors.IsEnabled(composition, ConstructorKind.Scope) && composition.IsFactoryMethod;
2221
var skipFieldsInit = isAnyConstructorEnabled && !hasScopeFactory;
2322
if (isAnyConstructorEnabled && composition.Singletons.Length > 0)
2423
{
@@ -27,7 +26,7 @@ public CompositionCode Build(CompositionCode composition)
2726
membersCounter++;
2827
}
2928

30-
if (composition.IsLockRequired(locks))
29+
if (composition.IsLockRequired)
3130
{
3231
// _lock field
3332
code.AppendLine(new Line(int.MinValue, "#if NET9_0_OR_GREATER"));
@@ -73,4 +72,4 @@ public CompositionCode Build(CompositionCode composition)
7372

7473
return composition with { MembersCount = membersCounter };
7574
}
76-
}
75+
}

src/Pure.DI.Core/Core/Code/Parts/ParameterizedConstructorBuilder.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ namespace Pure.DI.Core.Code.Parts;
55
sealed class ParameterizedConstructorBuilder(
66
ITypeResolver typeResolver,
77
[Tag(typeof(ParameterizedConstructorCommenter))] ICommenter<Unit> constructorCommenter,
8-
ILocks locks,
98
IConstructors constructors,
109
ICodeNameProvider codeNameProvider)
1110
: IClassPartBuilder
@@ -69,7 +68,7 @@ public CompositionCode Build(CompositionCode composition)
6968
code.AppendLine($"{Names.RootFieldName} = this;");
7069
}
7170

72-
if (composition.IsLockRequired(locks))
71+
if (composition.IsLockRequired)
7372
{
7473
code.AppendLine(new Line(int.MinValue, "#if NET9_0_OR_GREATER"));
7574
code.AppendLine($"{Names.LockFieldName} = new {Names.LockTypeName}();");

src/Pure.DI.Core/Core/Code/Parts/ScopeConstructorBuilder.cs

Lines changed: 7 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,7 @@
33
// ReSharper disable ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator
44
namespace Pure.DI.Core.Code.Parts;
55

6-
using Microsoft.CodeAnalysis.CSharp;
7-
using Microsoft.CodeAnalysis.CSharp.Syntax;
8-
96
sealed class ScopeConstructorBuilder(
10-
ILocks locks,
117
IConstructors constructors,
128
ICodeNameProvider codeNameProvider)
139
: IClassPartBuilder
@@ -24,20 +20,13 @@ public CompositionCode Build(CompositionCode composition)
2420
var code = composition.Code;
2521
var membersCounter = composition.MembersCount;
2622
var hints = composition.Source.Source.Hints;
27-
var setupContextMembersToCopy = GetSetupContextMembersToCopy(composition);
23+
var setupContextMembersToCopy = composition.SetupContextMembersToCopy;
2824
var classArgs = composition.ClassArgs.GetArgsOfKind(ArgKind.Composition).ToList();
29-
var setupContextArgsToCopy = composition.SetupContextArgs
30-
.Where(arg => arg.Kind != SetupContextKind.RootArgument)
31-
.ToList();
32-
var isLockRequired = composition.IsLockRequired(locks);
33-
var requiresParentScope = composition.Singletons.Length > 0
34-
|| classArgs.Count > 0
35-
|| setupContextArgsToCopy.Count > 0
36-
|| setupContextMembersToCopy.Count > 0
37-
|| isLockRequired
38-
|| composition.TotalDisposablesCount > 0;
39-
var scopeFactoryName = hints.ScopeFactoryName;
40-
var isFactoryMethod = requiresParentScope && !string.IsNullOrWhiteSpace(scopeFactoryName);
25+
var setupContextArgsToCopy = composition.SetupContextArgsToCopy;
26+
var isLockRequired = composition.IsLockRequired;
27+
var requiresParentScope = composition.RequiresParentScope;
28+
var scopeFactoryName = composition.ScopeFactoryName;
29+
var isFactoryMethod = composition.IsFactoryMethod;
4130
var isCommentsEnabled = hints.IsCommentsEnabled;
4231
string source, destination;
4332
if (isFactoryMethod)
@@ -65,7 +54,7 @@ public CompositionCode Build(CompositionCode composition)
6554

6655
source = $"{Names.ParentScopeArgName}.";
6756
destination = "";
68-
var ctorName = isFactoryMethod ? scopeFactoryName : codeNameProvider.GetConstructorName(composition.Source.Source.Name.ClassName);
57+
var ctorName = codeNameProvider.GetConstructorName(composition.Source.Source.Name.ClassName);
6958
code.AppendLine($"internal {ctorName}({composition.Source.Source.Name.ClassName} {Names.ParentScopeArgName})");
7059
}
7160

@@ -138,50 +127,4 @@ public CompositionCode Build(CompositionCode composition)
138127
membersCounter++;
139128
return composition with { MembersCount = membersCounter };
140129
}
141-
142-
private static IReadOnlyCollection<string> GetSetupContextMembersToCopy(CompositionCode composition)
143-
{
144-
var memberNames = new HashSet<string>(StringComparer.Ordinal);
145-
foreach (var setupContextMembers in composition.SetupContextMembers)
146-
{
147-
foreach (var member in setupContextMembers.Members)
148-
{
149-
switch (member)
150-
{
151-
case FieldDeclarationSyntax { Declaration: { } declaration }:
152-
foreach (var variable in declaration.Variables)
153-
{
154-
if (!variable.Identifier.IsKind(SyntaxKind.None))
155-
{
156-
memberNames.Add(variable.Identifier.ValueText);
157-
}
158-
}
159-
160-
break;
161-
162-
case PropertyDeclarationSyntax property when IsPropertyAssignable(property):
163-
if (!property.Identifier.IsKind(SyntaxKind.None))
164-
{
165-
memberNames.Add(property.Identifier.ValueText);
166-
}
167-
168-
break;
169-
}
170-
}
171-
}
172-
173-
return memberNames;
174-
}
175-
176-
private static bool IsPropertyAssignable(PropertyDeclarationSyntax property)
177-
{
178-
if (property.ExpressionBody is not null || property.AccessorList is not { } accessorList)
179-
{
180-
return false;
181-
}
182-
183-
return accessorList.Accessors.Any(accessor =>
184-
accessor.Kind() is SyntaxKind.SetAccessorDeclaration or SyntaxKind.InitAccessorDeclaration)
185-
|| accessorList.Accessors.All(accessor => accessor.Body is null && accessor.ExpressionBody is null);
186-
}
187130
}

src/Pure.DI.Core/Core/Models/CompositionCode.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,13 @@ record CompositionCode(
1414
in ImmutableArray<VarDeclaration> ClassArgs,
1515
in ImmutableArray<SetupContextArg> SetupContextArgs,
1616
in ImmutableArray<SetupContextMembers> SetupContextMembers,
17+
in ImmutableArray<SetupContextArg> SetupContextArgsToCopy,
18+
in ImmutableArray<string> SetupContextMembersToCopy,
19+
string ScopeFactoryName,
20+
bool IsFactoryMethod,
21+
bool RequiresParentScope,
22+
bool IsLockRequired,
1723
int MembersCount = 0)
1824
{
1925
public Compilation Compilation => Source.Source.SemanticModel.Compilation;
20-
21-
public bool IsLockRequired(ILocks locks) => IsThreadSafe || locks.HasLockField(Source);
2226
}

0 commit comments

Comments
 (0)