Skip to content

Commit 40abe56

Browse files
committed
from MetadataReferencesProvider
1 parent baf58eb commit 40abe56

File tree

2 files changed

+147
-37
lines changed

2 files changed

+147
-37
lines changed

sandbox/GeneratorSandbox/Program.cs

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,24 @@
11
using ConsoleAppFramework;
22
using FilterShareProject;
3-
using Microsoft.Extensions.DependencyInjection;
3+
//using Microsoft.Extensions.DependencyInjection;
4+
using System.Runtime.CompilerServices;
45

56

67
args = ["Output"];
78

8-
var app = ConsoleApp.Create();
99

1010
// ConsoleApp.ServiceProvider
1111
// ConsoleApp.Create(
1212

13-
ConsoleApp.Create(sc =>
14-
{
15-
16-
});
1713

18-
app.Add<MyCommands>();
14+
var app = ConsoleApp.Create();
15+
16+
// var app = ConsoleApp.Create();
1917

20-
app.Run(args);
18+
// app.Add<MyCommands>();
19+
// app.Add<MyCommands>();
20+
21+
// app.Run(args);
2122

2223

2324

@@ -49,6 +50,12 @@ public void Output(string msg = @"\\")
4950
}
5051
}
5152

53+
[HogeHoge.Batch2Attribute]
54+
public class Tacommands
55+
{
56+
57+
}
58+
5259
namespace ConsoleAppFramework
5360
{
5461
internal static partial class ConsoleApp
@@ -66,5 +73,43 @@ internal static partial class ConsoleApp
6673
// ConsoleApp.ServiceProvider = services.BuildServiceProvider();
6774
// return ConsoleApp.Create();
6875
//}
76+
77+
78+
79+
//internal partial struct ConsoleAppBuilder
80+
//{
81+
// /// <summary>
82+
// /// Add all [RegisterCommands] types as ConsoleApp command.
83+
// /// </summary>
84+
// public void RegisterAll()
85+
// {
86+
// }
87+
88+
// /// <summary>
89+
// /// Add all [RegisterCommands] types as ConsoleApp command.
90+
// /// </summary>
91+
// public void RegisterAll(string commandPath)
92+
// {
93+
// }
94+
95+
//}
96+
}
97+
98+
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
99+
internal sealed class RegisterCommandsAttribute : Attribute
100+
{
101+
public string CommandPath { get; set; } = "";
102+
}
103+
}
104+
105+
namespace HogeHoge
106+
{
107+
public class BatchAttribute : Attribute
108+
{
109+
}
110+
111+
112+
public class Batch2Attribute : BatchAttribute
113+
{
69114
}
70115
}

src/ConsoleAppFramework/ConsoleAppGenerator.cs

Lines changed: 94 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,17 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
1313
{
1414
context.RegisterPostInitializationOutput(EmitConsoleAppTemplateSource);
1515

16+
// ConsoleApp.Create(Action<IServiceCollection> configure)
17+
var hasDependencyInjection = context.MetadataReferencesProvider
18+
.Where(x =>
19+
{
20+
return x.Display?.EndsWith("Microsoft.Extensions.DependencyInjection.Abstractions.dll") ?? false;
21+
})
22+
.Collect()
23+
.Select((x, ct) => x.Any());
24+
25+
context.RegisterSourceOutput(hasDependencyInjection, EmitConsoleAppCreateConfigure);
26+
1627
// ConsoleApp.Run
1728
var runSource = context.SyntaxProvider
1829
.CreateSyntaxProvider((node, ct) =>
@@ -81,13 +92,22 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
8192
.Where(x =>
8293
{
8394
var model = x.Model.GetTypeInfo((x.Node.Expression as MemberAccessExpressionSyntax)!.Expression, x.CancellationToken);
84-
return model.Type?.Name == "ConsoleAppBuilder";
95+
return model.Type?.Name is "ConsoleAppBuilder";
8596
})
8697
.WithTrackingName("ConsoleApp.Builder.1_Where")
8798
.Collect()
8899
.Select((x, ct) => new CollectBuilderContext(x, ct))
89100
.WithTrackingName("ConsoleApp.Builder.2_Collect");
90101

102+
// WIP
103+
//var registerCommands = context.SyntaxProvider.ForAttributeWithMetadataName("ConsoleAppFramework.RegisterCommandsAttribute",
104+
// (node, token) => true,
105+
// (ctx, token) => ctx)
106+
// .Collect()
107+
// .Select((x, token) => new CollectBuilderContext(default, token));
108+
109+
//var lr = builderSource.Combine(registerCommands); // combine with registerCommands
110+
91111
context.RegisterSourceOutput(builderSource, EmitConsoleAppBuilder);
92112
}
93113

@@ -673,26 +693,37 @@ static void EmitConsoleAppBuilder(SourceProductionContext sourceProductionContex
673693
emitter.EmitHelp(help, commandIds!);
674694
}
675695
sourceProductionContext.AddSource("ConsoleApp.Builder.Help.g.cs", help.ToString());
696+
}
676697

677-
// emit Create(IServiceCollection) if exists Microsoft.Extensions.DependencyInjection.ServiceCollection
678-
if (collectBuilderContext.HasDependencyInjectionReference)
698+
static void EmitConsoleAppCreateConfigure(SourceProductionContext sourceProductionContext, bool hasDependencyInjection)
699+
{
700+
var code = """
701+
// <auto-generated/>
702+
#nullable enable
703+
namespace ConsoleAppFramework;
704+
705+
using System;
706+
using Microsoft.Extensions.DependencyInjection;
707+
708+
internal static partial class ConsoleApp
709+
{
710+
public static ConsoleAppBuilder Create(Action<IServiceCollection> configure)
711+
{
712+
var services = new ServiceCollection();
713+
configure(services);
714+
ConsoleApp.ServiceProvider = services.BuildServiceProvider();
715+
return ConsoleApp.Create();
716+
}
717+
}
718+
""";
719+
720+
// emit empty if not exists
721+
if (!hasDependencyInjection)
679722
{
680-
var runBuilder = new SourceBuilder(0);
681-
runBuilder.AppendLine(GeneratedCodeHeader);
682-
runBuilder.AppendLine("using Microsoft.Extensions.DependencyInjection");
683-
runBuilder.AppendLine();
684-
using (runBuilder.BeginBlock("internal static partial class ConsoleApp"))
685-
{
686-
using (runBuilder.BeginBlock("public static ConsoleAppBuilder Create(Action<IServiceCollection> configure)"))
687-
{
688-
runBuilder.AppendLine("var services = new ServiceCollection();");
689-
runBuilder.AppendLine("configure(services);");
690-
runBuilder.AppendLine("ConsoleApp.ServiceProvider = services.BuildServiceProvider();");
691-
runBuilder.AppendLine("return ConsoleApp.Create();");
692-
}
693-
}
694-
sourceProductionContext.AddSource("ConsoleApp.Builder.Run.g.cs", runBuilder.ToString());
723+
code = "";
695724
}
725+
726+
sourceProductionContext.AddSource("ConsoleApp.Create.g.cs", code);
696727
}
697728

698729
class CommanContext(Command? command, bool isAsync, DiagnosticReporter diagnosticReporter, InvocationExpressionSyntax node) : IEquatable<CommanContext>
@@ -720,18 +751,12 @@ class CollectBuilderContext : IEquatable<CollectBuilderContext>
720751
public CancellationToken CancellationToken { get; }
721752
public bool HasRun { get; }
722753
public bool HasRunAsync { get; }
723-
public bool HasDependencyInjectionReference { get; }
724754

725755
public CollectBuilderContext(ImmutableArray<BuilderContext> contexts, CancellationToken cancellationToken)
726756
{
727757
this.DiagnosticReporter = new DiagnosticReporter();
728758
this.CancellationToken = cancellationToken;
729759

730-
if (contexts.Length == 0)
731-
{
732-
return;
733-
}
734-
735760
// validation, invoke in loop is not allowed.
736761
foreach (var item in contexts)
737762
{
@@ -832,18 +857,58 @@ public CollectBuilderContext(ImmutableArray<BuilderContext> contexts, Cancellati
832857
this.Commands = commands1.Concat(commands2!).ToArray()!; // not null if no diagnostics
833858
this.HasRun = methodGroup["Run"].Any();
834859
this.HasRunAsync = methodGroup["RunAsync"].Any();
835-
836-
var model = contexts[0].Model;
837-
var serviceCollectionSymbol = model.Compilation.GetTypeByMetadataName("Microsoft.Extensions.DependencyInjection.ServiceCollection");
838-
this.HasDependencyInjectionReference = serviceCollectionSymbol != null;
860+
}
861+
862+
// from ForAttributeWithMetadataName
863+
public void AddRegisterAttributes(ImmutableArray<GeneratorAttributeSyntaxContext> contexts)
864+
{
865+
if (contexts.Length == 0)
866+
{
867+
return;
868+
}
869+
870+
//var names = new HashSet<string>();
871+
872+
//var commands2 = methodGroup["Add<T>"]
873+
// .SelectMany(x =>
874+
// {
875+
// var wellKnownTypes = new WellKnownTypes(x.Model.Compilation);
876+
// var parser = new Parser(DiagnosticReporter, x.Node, x.Model, wellKnownTypes, DelegateBuildType.None, globalFilters);
877+
// var commands = parser.ParseAndValidateForBuilderClassRegistration();
878+
879+
// // validation command name duplicate
880+
// foreach (var command in commands)
881+
// {
882+
// if (command != null && !names.Add(command.Name))
883+
// {
884+
// DiagnosticReporter.ReportDiagnostic(DiagnosticDescriptors.DuplicateCommandName, x.Node.GetLocation(), command!.Name);
885+
// return [null];
886+
// }
887+
// }
888+
889+
// return commands;
890+
// });
891+
892+
//if (DiagnosticReporter.HasDiagnostics)
893+
//{
894+
// return;
895+
//}
896+
897+
//// set properties
898+
//this.Commands = commands1.Concat(commands2!).ToArray()!; // not null if no diagnostics
899+
//this.HasRun = methodGroup["Run"].Any();
900+
//this.HasRunAsync = methodGroup["RunAsync"].Any();
901+
902+
//var model = contexts[0].Model;
903+
//var serviceCollectionSymbol = model.Compilation.GetTypeByMetadataName("Microsoft.Extensions.DependencyInjection.ServiceCollection");
904+
//this.HasDependencyInjectionReference = serviceCollectionSymbol != null;
839905
}
840906

841907
public bool Equals(CollectBuilderContext other)
842908
{
843909
if (DiagnosticReporter.HasDiagnostics || other.DiagnosticReporter.HasDiagnostics) return false;
844910
if (HasRun != other.HasRun) return false;
845911
if (HasRunAsync != other.HasRunAsync) return false;
846-
if (HasDependencyInjectionReference != other.HasDependencyInjectionReference) return false;
847912

848913
return Commands.AsSpan().SequenceEqual(other.Commands);
849914
}

0 commit comments

Comments
 (0)