diff --git a/src/Pure.DI.Core/Core/ApiInvocationProcessor.cs b/src/Pure.DI.Core/Core/ApiInvocationProcessor.cs index bdbdade06..b20b2a516 100644 --- a/src/Pure.DI.Core/Core/ApiInvocationProcessor.cs +++ b/src/Pure.DI.Core/Core/ApiInvocationProcessor.cs @@ -10,7 +10,6 @@ internal class ApiInvocationProcessor( : IApiInvocationProcessor { private static readonly char[] TypeNamePartsSeparators = ['.']; - private readonly Hints _hints = new(); public void ProcessInvocation( IMetadataVisitor metadataVisitor, @@ -92,7 +91,7 @@ public void ProcessInvocation( var hintArgs = arguments.GetArgs(invocation.ArgumentList, "hint", "value"); if (hintArgs is [{ Expression: { } hintNameExpression }, { Expression: { } hintValueExpression }]) { - _hints[semanticModel.GetConstantValue(hintNameExpression)] = semanticModel.GetRequiredConstantValue(hintValueExpression); + metadataVisitor.VisitHint(new MdHint(semanticModel.GetConstantValue(hintNameExpression), semanticModel.GetRequiredConstantValue(hintValueExpression))); } break; @@ -116,6 +115,11 @@ public void ProcessInvocation( setupCompositionTypeName = baseType.Identifier.Text; } + foreach (var hint in comments.GetHints(invocationComments)) + { + metadataVisitor.VisitHint(new MdHint(hint.Key, hint.Value)); + } + metadataVisitor.VisitSetup( new MdSetup( semanticModel, @@ -123,7 +127,7 @@ public void ProcessInvocation( CreateCompositionName(setupCompositionTypeName, @namespace, invocation.ArgumentList), ImmutableArray.Empty, setupKind, - ApplyHints(invocationComments), + new Hints(), ImmutableArray.Empty, ImmutableArray.Empty, ImmutableArray.Empty, @@ -507,16 +511,6 @@ private static void VisitUsingDirectives( } } - private IHints ApplyHints(IEnumerable invocationComments) - { - foreach (var hint in comments.GetHints(invocationComments)) - { - _hints[hint.Key] = hint.Value; - } - - return _hints; - } - // ReSharper disable once SuggestBaseTypeForParameter private static void NotSupported(InvocationExpressionSyntax invocation) { @@ -539,7 +533,7 @@ private static ImmutableArray BuildTags(SemanticModel semanticModel, IEnu .Select((tag, i) => new MdTag(i, tag)) .ToImmutableArray(); } - + private static CompositionName CreateCompositionName(string name, string ns, SyntaxNode source) { string className; diff --git a/src/Pure.DI.Core/Core/IMetadataVisitor.cs b/src/Pure.DI.Core/Core/IMetadataVisitor.cs index b2f0be325..bc0d8d8f9 100644 --- a/src/Pure.DI.Core/Core/IMetadataVisitor.cs +++ b/src/Pure.DI.Core/Core/IMetadataVisitor.cs @@ -15,7 +15,7 @@ internal interface IMetadataVisitor void VisitFactory(in MdFactory factory); - void VisitResolve(MdResolver resolver); + void VisitResolve(in MdResolver resolver); void VisitDefaultLifetime(in MdDefaultLifetime defaultLifetime); @@ -36,6 +36,8 @@ internal interface IMetadataVisitor void VisitTag(in MdTag tag); void VisitAccumulator(in MdAccumulator accumulator); + + void VisitHint(in MdHint hint); void VisitFinish(); } \ No newline at end of file diff --git a/src/Pure.DI.Core/Core/MetadataSyntaxWalker.cs b/src/Pure.DI.Core/Core/MetadataSyntaxWalker.cs index a46ec5334..51a82eac5 100644 --- a/src/Pure.DI.Core/Core/MetadataSyntaxWalker.cs +++ b/src/Pure.DI.Core/Core/MetadataSyntaxWalker.cs @@ -23,10 +23,12 @@ internal sealed class MetadataSyntaxWalker( public void Visit(IMetadataVisitor metadataVisitor, in SyntaxUpdate update) { Visit(update.Node); - var invocations = new Stack(); + var invocations = new List(); + var actions = new List(); + var reverserId = 0; while (_invocations.TryPop(out var invocation)) { - invocations.Push(invocation); + invocations.Add(new InvocationInfo(update.SemanticModel, invocation, new OrderedVisitor(actions, metadataVisitor, reverserId++))); _isMetadata = true; try { @@ -38,14 +40,32 @@ public void Visit(IMetadataVisitor metadataVisitor, in SyntaxUpdate update) } } - while (invocations.TryPop(out var invocation)) + if (invocations.Count == 0) { - invocationProcessor.ProcessInvocation(metadataVisitor, update.SemanticModel, invocation, _namespace); + return; } + invocations.Reverse(); +#if DEBUG + invocations.ForEach(ProcessInvocation); +#else + Parallel.ForEach(invocations, ProcessInvocation); +#endif + var orderedActions = actions + .OrderByDescending(i => i.Id) + .ThenBy(i => i.SubId); + + foreach (var action in orderedActions) + { + action.Run(); + } + metadataVisitor.VisitFinish(); } - + + private void ProcessInvocation(InvocationInfo invocation) => + invocationProcessor.ProcessInvocation(invocation.Visitor, invocation.SemanticModel, invocation.Invocation, _namespace); + // ReSharper disable once CognitiveComplexity public override void VisitInvocationExpression(InvocationExpressionSyntax invocation) { @@ -67,7 +87,7 @@ public override void VisitNamespaceDeclaration(NamespaceDeclarationSyntax namesp _namespace = namespaceDeclaration.Name.ToString().Trim(); base.VisitNamespaceDeclaration(namespaceDeclaration); } - + private static string GetInvocationName(InvocationExpressionSyntax invocation) => GetName(invocation.Expression, 2); private static string GetName(ExpressionSyntax expression, int deepness = int.MaxValue) @@ -76,7 +96,7 @@ private static string GetName(ExpressionSyntax expression, int deepness = int.Ma { case IdentifierNameSyntax identifierNameSyntax: return identifierNameSyntax.Identifier.Text; - + case MemberAccessExpressionSyntax memberAccess when memberAccess.IsKind(SyntaxKind.SimpleMemberAccessExpression): { var name = memberAccess.Name.Identifier.Text; @@ -88,16 +108,125 @@ private static string GetName(ExpressionSyntax expression, int deepness = int.Ma return name; } - + default: return string.Empty; } } - + [SuppressMessage("ReSharper", "SuggestBaseTypeForParameter")] private static bool IsMetadata(InvocationExpressionSyntax invocation) => invocation .DescendantNodesAndSelf() .OfType() .FirstOrDefault(i => GetInvocationName(i) == DISetup) is not null; + + private readonly record struct InvocationInfo( + SemanticModel SemanticModel, + InvocationExpressionSyntax Invocation, + IMetadataVisitor Visitor); + + private class OrderedVisitor( + ICollection actions, + IMetadataVisitor baseVisitor, + int id) + : IMetadataVisitor + { + private int _subId; + + public void VisitSetup(in MdSetup setup) => + AddAction(i => baseVisitor.VisitSetup(i), setup); + + public void VisitUsingDirectives(in MdUsingDirectives usingDirectives) => + AddAction(i => baseVisitor.VisitUsingDirectives(i), usingDirectives); + + public void VisitBinding(in MdBinding binding) => + AddAction(i => baseVisitor.VisitBinding(i), binding); + + public void VisitContract(in MdContract contract) => + AddAction(i => baseVisitor.VisitContract(i), contract); + + public void VisitImplementation(in MdImplementation implementation) => + AddAction(i => baseVisitor.VisitImplementation(i), implementation); + + public void VisitFactory(in MdFactory factory) => + AddAction(i => baseVisitor.VisitFactory(i), factory); + + public void VisitResolve(in MdResolver resolver) => + AddAction(i => baseVisitor.VisitResolve(i), resolver); + + public void VisitDefaultLifetime(in MdDefaultLifetime defaultLifetime) => + AddAction(i => baseVisitor.VisitDefaultLifetime(i), defaultLifetime); + + public void VisitDependsOn(in MdDependsOn dependsOn) => + AddAction(i => baseVisitor.VisitDependsOn(i), dependsOn); + + public void VisitArg(in MdArg arg) => + AddAction(i => baseVisitor.VisitArg(i), arg); + + public void VisitRoot(in MdRoot root) => + AddAction(i => baseVisitor.VisitRoot(i), root); + + public void VisitTypeAttribute(in MdTypeAttribute typeAttribute) => + AddAction(i => baseVisitor.VisitTypeAttribute(i), typeAttribute); + + public void VisitTagAttribute(in MdTagAttribute tagAttribute) => + AddAction(i => baseVisitor.VisitTagAttribute(i), tagAttribute); + + public void VisitOrdinalAttribute(in MdOrdinalAttribute ordinalAttribute) => + AddAction(i => baseVisitor.VisitOrdinalAttribute(i), ordinalAttribute); + + public void VisitLifetime(in MdLifetime lifetime) => + AddAction(i => baseVisitor.VisitLifetime(i), lifetime); + + public void VisitTag(in MdTag tag) => + AddAction(i => baseVisitor.VisitTag(i), tag); + + public void VisitAccumulator(in MdAccumulator accumulator) => + AddAction(i => baseVisitor.VisitAccumulator(i), accumulator); + + public void VisitHint(in MdHint hint) => + AddAction(i => baseVisitor.VisitHint(i), hint); + + public void VisitFinish() + { + lock (actions) + { + foreach (var action in actions.OrderBy(i => i.Id).ThenBy(i => i.SubId)) + { + action.Run(); + } + } + + baseVisitor.VisitFinish(); + } + + private void AddAction(Action action, in T state) + { + var visitorAction = new VisitorAction(action, state, id, _subId++); + lock (actions) + { + actions.Add(visitorAction); + } + } + + private record VisitorAction( + Action Action, + T State, + int Id, + int SubId) + : IRunnable + { + public void Run() => Action(State); + } + } + + private interface IRunnable + { + int Id { get; } + + int SubId { get; } + + void Run(); + } } \ No newline at end of file diff --git a/src/Pure.DI.Core/Core/MetadataWalkerBase.cs b/src/Pure.DI.Core/Core/MetadataWalkerBase.cs index 95096840a..17c46f9d9 100644 --- a/src/Pure.DI.Core/Core/MetadataWalkerBase.cs +++ b/src/Pure.DI.Core/Core/MetadataWalkerBase.cs @@ -106,7 +106,7 @@ public virtual void VisitRoot(in MdRoot root) } } - public virtual void VisitResolve(MdResolver resolver) + public virtual void VisitResolve(in MdResolver resolver) { if (resolver.Tag is {} tag) { @@ -154,6 +154,10 @@ public virtual void VisitAccumulator(in MdAccumulator accumulator) { } + public virtual void VisitHint(in MdHint hint) + { + } + public virtual void VisitFinish() { } diff --git a/src/Pure.DI.Core/Core/Models/MdHint.cs b/src/Pure.DI.Core/Core/Models/MdHint.cs new file mode 100644 index 000000000..03608f8ae --- /dev/null +++ b/src/Pure.DI.Core/Core/Models/MdHint.cs @@ -0,0 +1,3 @@ +namespace Pure.DI.Core.Models; + +internal readonly record struct MdHint(Hint Key, string Value); \ No newline at end of file diff --git a/src/Pure.DI.Core/Core/SetupsBuilder.cs b/src/Pure.DI.Core/Core/SetupsBuilder.cs index 077f35ad5..a4b836ef2 100644 --- a/src/Pure.DI.Core/Core/SetupsBuilder.cs +++ b/src/Pure.DI.Core/Core/SetupsBuilder.cs @@ -18,6 +18,7 @@ internal sealed class SetupsBuilder( private readonly List _accumulators = []; private IBindingBuilder _bindingBuilder = bindingBuilderFactory(); private MdSetup? _setup; + private Hints _hints = new(); public IEnumerable Build(SyntaxUpdate update) { @@ -69,7 +70,7 @@ public void VisitArg(in MdArg arg) FinishBinding(); } - public void VisitResolve(MdResolver resolver) + public void VisitResolve(in MdResolver resolver) { } @@ -98,6 +99,9 @@ public void VisitLifetime(in MdLifetime lifetime) => public void VisitAccumulator(in MdAccumulator accumulator) => _accumulators.Add(accumulator); + public void VisitHint(in MdHint hint) => + _hints[hint.Key] = hint.Value; + public void VisitFinish() => FinishSetup(); private void FinishBinding() => @@ -113,6 +117,7 @@ private void FinishSetup() _setups.Add( setup with { + Hints = _hints, Bindings = _bindings.Select(i => i with { SourceSetup = setup }).ToImmutableArray(), Roots = _roots.ToImmutableArray(), DependsOn = _dependsOn.ToImmutableArray(), @@ -122,7 +127,8 @@ setup with UsingDirectives = _usingDirectives.ToImmutableArray(), Accumulators = _accumulators.Distinct().ToImmutableArray() }); - + + _hints = new Hints(); _bindings.Clear(); _roots.Clear(); _dependsOn.Clear();