|
|
|
@ -19,6 +19,8 @@ public class FactoryGenerator : IIncrementalGenerator |
|
|
|
private const string GENERATED_FILE_HEADER = "//---GENERATED by FactoryGenerator! DO NOT EDIT!---"; |
|
|
|
private const string GENERATED_FILE_HEADER = "//---GENERATED by FactoryGenerator! DO NOT EDIT!---"; |
|
|
|
private const string INDENT = " "; |
|
|
|
private const string INDENT = " "; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private const string CLEAR_MULTITON_INSTANCE_METHOD_NAME = "ClearMultitonInstance"; |
|
|
|
|
|
|
|
|
|
|
|
public void Initialize(IncrementalGeneratorInitializationContext context) |
|
|
|
public void Initialize(IncrementalGeneratorInitializationContext context) |
|
|
|
{ |
|
|
|
{ |
|
|
|
string? classNamespace = typeof(FactoryGenerator).Namespace; |
|
|
|
string? classNamespace = typeof(FactoryGenerator).Namespace; |
|
|
|
@ -27,6 +29,7 @@ public class FactoryGenerator : IIncrementalGenerator |
|
|
|
IncrementalValuesProvider<ITypeSymbol?> syntaxProvider = context.SyntaxProvider.CreateSyntaxProvider(IsCallToGenerateFactory, GetTypeArgument); |
|
|
|
IncrementalValuesProvider<ITypeSymbol?> syntaxProvider = context.SyntaxProvider.CreateSyntaxProvider(IsCallToGenerateFactory, GetTypeArgument); |
|
|
|
|
|
|
|
|
|
|
|
context.RegisterSourceOutput(syntaxProvider.Collect(), GenerateTypeDependentClasses); |
|
|
|
context.RegisterSourceOutput(syntaxProvider.Collect(), GenerateTypeDependentClasses); |
|
|
|
|
|
|
|
context.RegisterSourceOutput(syntaxProvider, GenerateFactory); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private string GenerateFactoryExtensionsClass(string? classNamespace, string className) |
|
|
|
private string GenerateFactoryExtensionsClass(string? classNamespace, string className) |
|
|
|
@ -149,9 +152,130 @@ public class FactoryGenerator : IIncrementalGenerator |
|
|
|
return stringBuilder.ToString(); |
|
|
|
return stringBuilder.ToString(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private string GenerateFactorySourceCode(ITypeSymbol typeSymbol) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
string typeName = typeSymbol.Name; |
|
|
|
|
|
|
|
string? typeNamespace = typeSymbol.ContainingNamespace.IsGlobalNamespace ? null : typeSymbol.ContainingNamespace.ToString(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
StringBuilder stringBuilder = new(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stringBuilder.AppendLine(GENERATED_FILE_HEADER); |
|
|
|
|
|
|
|
stringBuilder.AppendLine(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stringBuilder.AppendLine("using LightweightIocContainer;"); |
|
|
|
|
|
|
|
stringBuilder.AppendLine(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (typeNamespace is not null) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
stringBuilder.AppendLine($"namespace {typeNamespace};"); |
|
|
|
|
|
|
|
stringBuilder.AppendLine(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stringBuilder.AppendLine($"public class Generated{typeName}(IocContainer container) : {typeName}"); |
|
|
|
|
|
|
|
stringBuilder.AppendLine("{"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
foreach (ISymbol? member in typeSymbol.GetMembers()) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (member is not IMethodSymbol method) |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stringBuilder.AppendLine(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!method.ReturnsVoid) //create method |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
stringBuilder.Append($"{INDENT}public {method.ReturnType.Name} {method.Name}"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (method.IsGenericMethod) |
|
|
|
|
|
|
|
stringBuilder.Append($"<{string.Join(", ", method.TypeParameters.Select(p => p.Name))}>"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stringBuilder.Append($"({string.Join(", ", method.Parameters.Select(GetParameterText))})"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (method.IsGenericMethod) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
foreach (ITypeParameterSymbol typeParameter in method.TypeParameters) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
List<string> parameterConstraints = GetParameterConstraints(typeParameter); |
|
|
|
|
|
|
|
if (parameterConstraints.Count == 0) |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stringBuilder.Append($" where {typeParameter.Name} : {string.Join(", ", parameterConstraints)}"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stringBuilder.AppendLine(); |
|
|
|
|
|
|
|
stringBuilder.AppendLine($"{INDENT}{{"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
foreach (IParameterSymbol parameter in method.Parameters) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
stringBuilder.AppendLine($"{INDENT}{INDENT}object? {parameter.Name}Value = {parameter.Name}"); |
|
|
|
|
|
|
|
stringBuilder.AppendLine($"{INDENT}{INDENT}if ({parameter.Name}Value is null)"); |
|
|
|
|
|
|
|
stringBuilder.AppendLine($"{INDENT}{INDENT}{INDENT}{parameter.Name}Value = new NullParameter(typeof({parameter.Type.Name}));"); |
|
|
|
|
|
|
|
stringBuilder.AppendLine(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (method.IsAsync) |
|
|
|
|
|
|
|
stringBuilder.Append($"{INDENT}{INDENT}return await container.ResolveAsync<>("); //TODO: Get return type from Task<> |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
stringBuilder.Append($"{INDENT}{INDENT}return container.Resolve<{method.ReturnType.Name}>("); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stringBuilder.Append(string.Join(", ", method.Parameters.Select(p => $"{p.Name}Value"))); |
|
|
|
|
|
|
|
stringBuilder.AppendLine(");"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stringBuilder.AppendLine($"{INDENT}}}"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else if (method.Name == CLEAR_MULTITON_INSTANCE_METHOD_NAME) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
//TODO |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typeSymbol.GetMembers(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stringBuilder.AppendLine("}"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return stringBuilder.ToString(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private IEnumerable<string> GetNamespacesOfTypes(ImmutableArray<ITypeSymbol?> types) => |
|
|
|
private IEnumerable<string> GetNamespacesOfTypes(ImmutableArray<ITypeSymbol?> types) => |
|
|
|
types.OfType<ITypeSymbol>() |
|
|
|
types.OfType<ITypeSymbol>() |
|
|
|
.Select(s => s.ContainingNamespace.IsGlobalNamespace ? null : s.ContainingNamespace.ToString()) |
|
|
|
.Select(s => s.ContainingNamespace.IsGlobalNamespace ? null : s.ContainingNamespace.ToString()) |
|
|
|
.OfType<string>() |
|
|
|
.OfType<string>() |
|
|
|
.Distinct(); |
|
|
|
.Distinct(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private string GetParameterText(IParameterSymbol parameter) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
StringBuilder stringBuilder = new(); |
|
|
|
|
|
|
|
stringBuilder.Append(parameter.Type.Name); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (parameter.NullableAnnotation == NullableAnnotation.Annotated) |
|
|
|
|
|
|
|
stringBuilder.Append("?"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stringBuilder.Append($" {parameter.Name}"); |
|
|
|
|
|
|
|
return stringBuilder.ToString(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private List<string> GetParameterConstraints(ITypeParameterSymbol typeParameterSymbol) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
List<string> constraints = []; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
foreach (ITypeSymbol constraintType in typeParameterSymbol.ConstraintTypes) |
|
|
|
|
|
|
|
constraints.Add(constraintType.Name); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (typeParameterSymbol.HasReferenceTypeConstraint) |
|
|
|
|
|
|
|
constraints.Add("class"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (typeParameterSymbol.HasValueTypeConstraint) |
|
|
|
|
|
|
|
constraints.Add("struct"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (typeParameterSymbol.HasConstructorConstraint) |
|
|
|
|
|
|
|
constraints.Add("new()"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (typeParameterSymbol.HasUnmanagedTypeConstraint) |
|
|
|
|
|
|
|
constraints.Add("unmanaged"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (typeParameterSymbol.HasNotNullConstraint) |
|
|
|
|
|
|
|
constraints.Add("notnull"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return constraints; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |